add direct mode to Program builder - close #61
This commit is contained in:
parent
9bf4b8fa96
commit
ea2b1e73d1
5
build_tests/direct/c_program.rb
Normal file
5
build_tests/direct/c_program.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Program("test.exe", Rscons.glob("*.c"), direct: true)
|
||||||
|
end
|
||||||
|
end
|
7
build_tests/direct/c_shared_library.rb
Normal file
7
build_tests/direct/c_shared_library.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
lib = env.SharedLibrary("mylib", ["two.c", "three.c"], direct: true)
|
||||||
|
program = env.Program("test.exe", "main.c", "LIBS" => ["mylib"], "LIBPATH" => ["."])
|
||||||
|
env.depends(program, lib)
|
||||||
|
end
|
||||||
|
end
|
7
build_tests/direct/main.c
Normal file
7
build_tests/direct/main.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "two.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
two();
|
||||||
|
return 0;
|
||||||
|
}
|
7
build_tests/direct/three.c
Normal file
7
build_tests/direct/three.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "three.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void three(void)
|
||||||
|
{
|
||||||
|
printf("three\n");
|
||||||
|
}
|
1
build_tests/direct/three.h
Normal file
1
build_tests/direct/three.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
void three(void);
|
7
build_tests/direct/two.c
Normal file
7
build_tests/direct/two.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "two.h"
|
||||||
|
#include "three.h"
|
||||||
|
|
||||||
|
void two(void)
|
||||||
|
{
|
||||||
|
three();
|
||||||
|
}
|
1
build_tests/direct/two.h
Normal file
1
build_tests/direct/two.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
void two(void);
|
@ -1,2 +1,2 @@
|
|||||||
Rscons::Builders::Object.register(command: "${ASCMD}", suffix: "${ASSUFFIX}", short_description: "Assembling")
|
Rscons::Builders::Object.register(command: "${ASCMD}", direct_command: "${ASCMD:direct}", suffix: "${ASSUFFIX}", short_description: "Assembling")
|
||||||
Rscons::Builders::SharedObject.register(command: "${ASCMD}", suffix: "${ASSUFFIX}", short_description: "Assembling")
|
Rscons::Builders::SharedObject.register(command: "${ASCMD}", direct_command: "${ASCMD:direct}", suffix: "${ASSUFFIX}", short_description: "Assembling")
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Rscons::Builders::Object.register(command: "${CCCMD}", suffix: "${CSUFFIX}")
|
Rscons::Builders::Object.register(command: "${CCCMD}", direct_command: "${CCCMD:direct}", suffix: "${CSUFFIX}")
|
||||||
Rscons::Builders::SharedObject.register(command: "${SHCCCMD}", suffix: "${CSUFFIX}")
|
Rscons::Builders::SharedObject.register(command: "${SHCCCMD}", direct_command: "${SHCCCMD:direct}", suffix: "${CSUFFIX}")
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Rscons::Builders::Object.register(command: "${CXXCMD}", suffix: "${CXXSUFFIX}", preferred_ld: "${CXX}")
|
Rscons::Builders::Object.register(command: "${CXXCMD}", direct_command: "${CXXCMD:direct}", suffix: "${CXXSUFFIX}", preferred_ld: "${CXX}")
|
||||||
Rscons::Builders::SharedObject.register(command: "${SHCXXCMD}", suffix: "${CXXSUFFIX}", preferred_ld: "${SHCXX}")
|
Rscons::Builders::SharedObject.register(command: "${SHCXXCMD}", direct_command: "${SHCXXCMD:direct}", suffix: "${CXXSUFFIX}", preferred_ld: "${SHCXX}")
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
Rscons::Builders::Object.register(command: "${DCCMD}", suffix: "${DSUFFIX}", preferred_ld: "${DC}")
|
Rscons::Builders::Object.register(command: "${DCCMD}", direct_command: "${DCCMD:direct}", suffix: "${DSUFFIX}", preferred_ld: "${DC}")
|
||||||
Rscons::Builders::SharedObject.register(command: "${SHDCCMD}", suffix: "${DSUFFIX}", preferred_ld: "${SHDC}")
|
Rscons::Builders::SharedObject.register(command: "${SHDCCMD}", direct_command: "${SHDCCMD:direct}", suffix: "${DSUFFIX}", preferred_ld: "${SHDC}")
|
||||||
|
@ -55,7 +55,12 @@ module Rscons
|
|||||||
unless build_params
|
unless build_params
|
||||||
raise "Unknown input file type: #{@sources.first.inspect}"
|
raise "Unknown input file type: #{@sources.first.inspect}"
|
||||||
end
|
end
|
||||||
@command_template = build_params[:command]
|
@command_template =
|
||||||
|
if @vars[:direct]
|
||||||
|
build_params[:direct_command]
|
||||||
|
else
|
||||||
|
build_params[:command]
|
||||||
|
end
|
||||||
@short_description = build_params[:short_description] || "Compiling"
|
@short_description = build_params[:short_description] || "Compiling"
|
||||||
@preferred_ld = build_params[:preferred_ld]
|
@preferred_ld = build_params[:preferred_ld]
|
||||||
end
|
end
|
||||||
@ -67,10 +72,21 @@ module Rscons
|
|||||||
else
|
else
|
||||||
@vars["_TARGET"] = @target
|
@vars["_TARGET"] = @target
|
||||||
@vars["_SOURCES"] = @sources
|
@vars["_SOURCES"] = @sources
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
depfilesuffix = @env.expand_varref("${DEPFILESUFFIX}", vars)
|
||||||
|
@vars["_DEPFILE"] =
|
||||||
|
if @vars[:direct]
|
||||||
|
@env.get_build_fname(target, depfilesuffix, self.class)
|
||||||
|
else
|
||||||
|
Rscons.set_suffix(target, depfilesuffix)
|
||||||
|
end
|
||||||
|
@cache.mkdir_p(File.dirname(@vars["_DEPFILE"]))
|
||||||
command = @env.build_command(@command_template, @vars)
|
command = @env.build_command(@command_template, @vars)
|
||||||
@env.produces(@target, @vars["_DEPFILE"])
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
message = "#{@short_description} #{Util.short_format_paths(@sources)}"
|
if @vars[:direct]
|
||||||
|
message = "#{@short_description}/Linking #{Util.short_format_paths(@sources)} => #{@target}"
|
||||||
|
else
|
||||||
|
message = "#{@short_description} #{Util.short_format_paths(@sources)}"
|
||||||
|
end
|
||||||
standard_command(message, command)
|
standard_command(message, command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,12 +7,22 @@ module Rscons
|
|||||||
include Mixins::ObjectDeps
|
include Mixins::ObjectDeps
|
||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def new(options, *more)
|
||||||
|
unless File.basename(options[:target])["."]
|
||||||
|
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
||||||
|
end
|
||||||
|
if options[:vars][:direct]
|
||||||
|
Object.new(options, *more)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
super(options)
|
super(options)
|
||||||
unless File.basename(@target)["."]
|
|
||||||
@target += @env.expand_varref("${PROGSUFFIX}", @vars)
|
|
||||||
end
|
|
||||||
@objects = register_object_deps(Object)
|
@objects = register_object_deps(Object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -7,16 +7,26 @@ module Rscons
|
|||||||
include Mixins::ObjectDeps
|
include Mixins::ObjectDeps
|
||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def new(options, *more)
|
||||||
|
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
||||||
|
unless File.basename(options[:target]).start_with?(libprefix)
|
||||||
|
options[:target] = options[:target].sub!(%r{^(.*/)?([^/]+)$}, "\\1#{libprefix}\\2")
|
||||||
|
end
|
||||||
|
unless File.basename(options[:target])["."]
|
||||||
|
options[:target] += options[:env].expand_varref("${SHLIBSUFFIX}", options[:vars])
|
||||||
|
end
|
||||||
|
if options[:vars][:direct]
|
||||||
|
SharedObject.new(options, *more)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
super(options)
|
super(options)
|
||||||
libprefix = @env.expand_varref("${SHLIBPREFIX}", @vars)
|
|
||||||
unless File.basename(@target).start_with?(libprefix)
|
|
||||||
@target = @target.sub!(%r{^(.*/)?([^/]+)$}, "\\1#{libprefix}\\2")
|
|
||||||
end
|
|
||||||
unless File.basename(@target)["."]
|
|
||||||
@target += @env.expand_varref("${SHLIBSUFFIX}", @vars)
|
|
||||||
end
|
|
||||||
@objects = register_object_deps(SharedObject)
|
@objects = register_object_deps(SharedObject)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ module Rscons
|
|||||||
"ARFLAGS" => %w[rcs],
|
"ARFLAGS" => %w[rcs],
|
||||||
"AS" => "${CC}",
|
"AS" => "${CC}",
|
||||||
"ASCMD" => %w[${AS} -c -o ${_TARGET} ${ASDEPGEN} ${INCPREFIX}${ASPPPATH} ${ASPPFLAGS} ${ASFLAGS} ${_SOURCES}],
|
"ASCMD" => %w[${AS} -c -o ${_TARGET} ${ASDEPGEN} ${INCPREFIX}${ASPPPATH} ${ASPPFLAGS} ${ASFLAGS} ${_SOURCES}],
|
||||||
|
"ASCMD:direct" => %w[${AS} -o ${_TARGET} ${ASDEPGEN} ${INCPREFIX}${ASPPPATH} ${ASPPFLAGS} ${ASFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"ASDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
"ASDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
||||||
"ASFLAGS" => [],
|
"ASFLAGS" => [],
|
||||||
"ASPPFLAGS" => "${CPPFLAGS}",
|
"ASPPFLAGS" => "${CPPFLAGS}",
|
||||||
@ -17,6 +18,7 @@ module Rscons
|
|||||||
"ASSUFFIX" => %w[.S],
|
"ASSUFFIX" => %w[.S],
|
||||||
"CC" => "gcc",
|
"CC" => "gcc",
|
||||||
"CCCMD" => %w[${CC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CFLAGS} ${CCFLAGS} ${_SOURCES}],
|
"CCCMD" => %w[${CC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CFLAGS} ${CCFLAGS} ${_SOURCES}],
|
||||||
|
"CCCMD:direct" => %w[${CC} -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CFLAGS} ${CCFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"CCDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
"CCDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
||||||
"CCFLAGS" => [],
|
"CCFLAGS" => [],
|
||||||
"CFLAGS" => [],
|
"CFLAGS" => [],
|
||||||
@ -28,11 +30,13 @@ module Rscons
|
|||||||
"CSUFFIX" => %w[.c],
|
"CSUFFIX" => %w[.c],
|
||||||
"CXX" => "g++",
|
"CXX" => "g++",
|
||||||
"CXXCMD" => %w[${CXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CXXFLAGS} ${CCFLAGS} ${_SOURCES}],
|
"CXXCMD" => %w[${CXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CXXFLAGS} ${CCFLAGS} ${_SOURCES}],
|
||||||
|
"CXXCMD:direct" => %w[${CXX} -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CXXFLAGS} ${CCFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"CXXDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
"CXXDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
||||||
"CXXFLAGS" => [],
|
"CXXFLAGS" => [],
|
||||||
"CXXSUFFIX" => %w[.cc .cpp .cxx .C],
|
"CXXSUFFIX" => %w[.cc .cpp .cxx .C],
|
||||||
"DC" => "gdc",
|
"DC" => "gdc",
|
||||||
"DCCMD" => %w[${DC} -c -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
|
"DCCMD" => %w[${DC} -c -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
|
||||||
|
"DCCMD:direct" => %w[${DC} -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"DDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
"DDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
|
||||||
"DEPFILESUFFIX" => ".mf",
|
"DEPFILESUFFIX" => ".mf",
|
||||||
"DFLAGS" => [],
|
"DFLAGS" => [],
|
||||||
@ -58,13 +62,16 @@ module Rscons
|
|||||||
"PROGSUFFIX" => on_windows ? ".exe" : "",
|
"PROGSUFFIX" => on_windows ? ".exe" : "",
|
||||||
"SHCC" => "${CC}",
|
"SHCC" => "${CC}",
|
||||||
"SHCCCMD" => %w[${SHCC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCFLAGS} ${SHCCFLAGS} ${_SOURCES}],
|
"SHCCCMD" => %w[${SHCC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCFLAGS} ${SHCCFLAGS} ${_SOURCES}],
|
||||||
|
"SHCCCMD:direct" => %w[${SHCC} -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCFLAGS} ${SHCCFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"SHCCFLAGS" => %w[${CCFLAGS}] + pic_flags,
|
"SHCCFLAGS" => %w[${CCFLAGS}] + pic_flags,
|
||||||
"SHCFLAGS" => %w[${CFLAGS}],
|
"SHCFLAGS" => %w[${CFLAGS}],
|
||||||
"SHCXX" => "${CXX}",
|
"SHCXX" => "${CXX}",
|
||||||
"SHCXXCMD" => %w[${SHCXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCXXFLAGS} ${SHCCFLAGS} ${_SOURCES}],
|
"SHCXXCMD" => %w[${SHCXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCXXFLAGS} ${SHCCFLAGS} ${_SOURCES}],
|
||||||
|
"SHCXXCMD:direct" => %w[${SHCXX} -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCXXFLAGS} ${SHCCFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"SHCXXFLAGS" => %w[${CXXFLAGS}],
|
"SHCXXFLAGS" => %w[${CXXFLAGS}],
|
||||||
"SHDC" => "gdc",
|
"SHDC" => "gdc",
|
||||||
"SHDCCMD" => %w[${SHDC} -c -o ${_TARGET} ${INCPREFIX}${D_IMPORT_PATH} ${SHDFLAGS} ${_SOURCES}],
|
"SHDCCMD" => %w[${SHDC} -c -o ${_TARGET} ${INCPREFIX}${D_IMPORT_PATH} ${SHDFLAGS} ${_SOURCES}],
|
||||||
|
"SHDCCMD:direct" => %w[${SHDC} -o ${_TARGET} ${INCPREFIX}${D_IMPORT_PATH} ${SHDFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
|
||||||
"SHDFLAGS" => %w[${DFLAGS}] + pic_flags,
|
"SHDFLAGS" => %w[${DFLAGS}] + pic_flags,
|
||||||
"SHLD" => nil,
|
"SHLD" => nil,
|
||||||
"SHLDCMD" => %w[${SHLD} -o ${_TARGET} ${SHLDFLAGS} ${_SOURCES} ${SHLIBDIRPREFIX}${LIBPATH} ${SHLIBLINKPREFIX}${LIBS}],
|
"SHLDCMD" => %w[${SHLD} -o ${_TARGET} ${SHLDFLAGS} ${_SOURCES} ${SHLIBDIRPREFIX}${LIBPATH} ${SHLIBLINKPREFIX}${LIBS}],
|
||||||
|
@ -314,7 +314,7 @@ module Rscons
|
|||||||
end
|
end
|
||||||
target = expand_path(expand_varref(target))
|
target = expand_path(expand_varref(target))
|
||||||
sources = Array(sources).map do |source|
|
sources = Array(sources).map do |source|
|
||||||
source = source.target if sources.is_a?(Builder)
|
source = source.target if source.is_a?(Builder)
|
||||||
expand_path(expand_varref(source))
|
expand_path(expand_varref(source))
|
||||||
end.flatten
|
end.flatten
|
||||||
builder = @builders[method.to_s].new(
|
builder = @builders[method.to_s].new(
|
||||||
@ -507,7 +507,7 @@ module Rscons
|
|||||||
# @param short_description [String]
|
# @param short_description [String]
|
||||||
# Builder short description, printed if the echo mode is :short, or if
|
# Builder short description, printed if the echo mode is :short, or if
|
||||||
# there is no command.
|
# there is no command.
|
||||||
# @param command [Array<String>]
|
# @param command [Array<String>, nil]
|
||||||
# Builder command, printed if the echo mode is :command.
|
# Builder command, printed if the echo mode is :command.
|
||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
|
@ -2079,4 +2079,49 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "direct mode" do
|
||||||
|
it "allows calling Program builder in direct mode and passes all sources to the C compiler" do
|
||||||
|
test_dir("direct")
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "c_program.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to match %r{Compiling/Linking}
|
||||||
|
expect(File.exists?("test.exe")).to be_truthy
|
||||||
|
expect(`./test.exe`).to match /three/
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "c_program.rb")
|
||||||
|
expect(result.stdout).to eq ""
|
||||||
|
|
||||||
|
three_h = File.read("three.h", mode: "rb")
|
||||||
|
File.open("three.h", "wb") do |fh|
|
||||||
|
fh.write(three_h)
|
||||||
|
fh.puts("#define FOO 42")
|
||||||
|
end
|
||||||
|
result = run_rscons(rsconscript: "c_program.rb")
|
||||||
|
expect(result.stdout).to match %r{Compiling/Linking}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows calling SharedLibrary builder in direct mode and passes all sources to the C compiler" do
|
||||||
|
test_dir("direct")
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "c_shared_library.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to match %r{Compiling/Linking}
|
||||||
|
expect(File.exists?("test.exe")).to be_truthy
|
||||||
|
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw/ ? "" : "LD_LIBRARY_PATH=. ")
|
||||||
|
expect(`#{ld_library_path_prefix}./test.exe`).to match /three/
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "c_shared_library.rb")
|
||||||
|
expect(result.stdout).to eq ""
|
||||||
|
|
||||||
|
three_h = File.read("three.h", mode: "rb")
|
||||||
|
File.open("three.h", "wb") do |fh|
|
||||||
|
fh.write(three_h)
|
||||||
|
fh.puts("#define FOO 42")
|
||||||
|
end
|
||||||
|
result = run_rscons(rsconscript: "c_shared_library.rb")
|
||||||
|
expect(result.stdout).to match %r{Compiling/Linking}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user