From d92504797f50ea3a4abcd8f8d0ee1d903abca8af Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 7 Dec 2015 21:12:23 +0200 Subject: Can build simple Swift executables. --- compilers.py | 86 ++++++++++++++++++++++++++++++++++++++ environment.py | 21 ++++++++++ interpreter.py | 5 +++ run_tests.py | 1 + test cases/swift/1 exe/meson.build | 3 ++ test cases/swift/1 exe/prog.swift | 1 + 6 files changed, 117 insertions(+) create mode 100644 test cases/swift/1 exe/meson.build create mode 100644 test cases/swift/1 exe/prog.swift diff --git a/compilers.py b/compilers.py index 7907235d5..d29759255 100644 --- a/compilers.py +++ b/compilers.py @@ -92,6 +92,11 @@ mono_buildtype_args = {'plain' : [], 'debugoptimized': ['-debug', '-optimize+'], 'release' : ['-optimize+']} +swift_buildtype_args = {'plain' : [], + 'debug' : ['-g'], + 'debugoptimized': ['-g', '-O'], + 'release' : ['-O']} + gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32', '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32'] @@ -948,6 +953,87 @@ class RustCompiler(Compiler): def get_buildtype_args(self, buildtype): return rust_buildtype_args[buildtype] +class SwiftCompiler(Compiler): + def __init__(self, exelist, version): + super().__init__(exelist, version) + self.version = version + self.id = 'llvm' + self.language = 'swift' + self.is_cross = False + + def get_id(self): + return self.id + + def get_linker_exelist(self): + return self.exelist + + def name_string(self): + return ' '.join(self.exelist) + + def needs_static_linker(self): + return True + + def get_exelist(self): + return self.exelist + + def get_werror_args(self): + return ['--fatal-warnings'] + + def get_language(self): + return self.language + + def get_dependency_gen_args(self, outtarget, outfile): + return ['-emit-dependencies'] + + def get_depfile_suffix(self): + return 'd' + + def get_output_args(self, target): + return ['-o', target] + + def get_linker_output_args(self, target): + return ['-o', target] + + def get_warn_args(self, level): + return [] + + def get_buildtype_args(self, buildtype): + return swift_buildtype_args[buildtype] + + def get_buildtype_linker_args(self, buildtype): + return [] + + def get_std_exe_link_args(self): + return ['-emit-executable'] + + def build_rpath_args(self, *args): + return [] # FIXME + + def get_include_args(self, dirname): + return ['-I' + dirname] + + def get_compile_only_args(self): + return ['-c'] + + def sanity_check(self, work_dir): + src = 'swifttest.swift' + source_name = os.path.join(work_dir, src) + output_name = os.path.join(work_dir, 'swifttest') + ofile = open(source_name, 'w') + ofile.write('''1 + 2 +''') + ofile.close() + pc = subprocess.Popen(self.exelist + ['-emit-executable', '-o', output_name, src], cwd=work_dir) + pc.wait() + if pc.returncode != 0: + raise EnvironmentException('Swift compiler %s can not compile programs.' % self.name_string()) + if subprocess.call(output_name) != 0: + raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string()) + + def can_compile(self, filename): + suffix = filename.split('.')[-1] + return suffix in ('swift') + class VisualStudioCCompiler(CCompiler): std_warn_args = ['/W3'] std_opt_args= ['/O2'] diff --git a/environment.py b/environment.py index c92eb87f7..308a21ce6 100644 --- a/environment.py +++ b/environment.py @@ -19,6 +19,10 @@ import configparser build_filename = 'meson.build' +class EnvironmentException(coredata.MesonException): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + def find_coverage_tools(): gcovr_exe = 'gcovr' lcov_exe = 'lcov' @@ -457,6 +461,23 @@ class Environment(): return RustCompiler(exelist, version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') + def detect_swift_compiler(self): + exelist = ['swiftc'] + try: + p = subprocess.Popen(exelist + ['-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except OSError: + raise EnvironmentException('Could not execute Swift compiler "%s"' % ' '.join(exelist)) + (_, err) = p.communicate() + err = err.decode() + vmatch = re.search(Environment.version_regex, err) + if vmatch: + version = vmatch.group(0) + else: + version = 'unknown version' + if 'Swift' in err: + return SwiftCompiler(exelist, version) + raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') + def detect_static_linker(self, compiler): if compiler.is_cross: linker = self.cross_info.config['binaries']['ar'] diff --git a/interpreter.py b/interpreter.py index f4c09a485..c8c1c2672 100644 --- a/interpreter.py +++ b/interpreter.py @@ -1474,6 +1474,11 @@ class Interpreter(): comp = self.environment.detect_fortran_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_fortran_compiler(True) + elif lang == 'swift': + comp = self.environment.detect_swift_compiler() + if need_cross_compiler: + raise InterpreterException('Cross compilation with Swift is not working yet.') + #cross_comp = self.environment.detect_fortran_compiler(True) else: raise InvalidCode('Tried to use unknown language "%s".' % lang) comp.sanity_check(self.environment.get_scratch_dir()) diff --git a/run_tests.py b/run_tests.py index e84d6100a..f07e0667e 100755 --- a/run_tests.py +++ b/run_tests.py @@ -254,6 +254,7 @@ def detect_tests_to_run(): all_tests.append(('rust', gather_tests('test cases/rust'), False if shutil.which('rustc') else True)) all_tests.append(('objective c', gather_tests('test cases/objc'), False if not mesonlib.is_windows() else True)) all_tests.append(('fortran', gather_tests('test cases/fortran'), False if shutil.which('gfortran') else True)) + all_tests.append(('swift', gather_tests('test cases/swift'), False if shutil.which('swiftc') else True)) return all_tests def run_tests(extra_args): diff --git a/test cases/swift/1 exe/meson.build b/test cases/swift/1 exe/meson.build new file mode 100644 index 000000000..f986e9af5 --- /dev/null +++ b/test cases/swift/1 exe/meson.build @@ -0,0 +1,3 @@ +project('swift exe', 'swift') + +test('swifttest', executable('swifttest', 'prog.swift')) diff --git a/test cases/swift/1 exe/prog.swift b/test cases/swift/1 exe/prog.swift new file mode 100644 index 000000000..1b489de72 --- /dev/null +++ b/test cases/swift/1 exe/prog.swift @@ -0,0 +1 @@ +print("Swift executable is working.") -- cgit v1.2.3 From 7ed515dacc726b6413ff720b7c125670b60543a1 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 7 Dec 2015 21:52:08 +0200 Subject: Refactored dep file name so Swift dependency tracking works. --- compilers.py | 9 +++++++++ ninjabackend.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compilers.py b/compilers.py index d29759255..41c4ecd29 100644 --- a/compilers.py +++ b/compilers.py @@ -215,6 +215,9 @@ class CCompiler(Compiler): def get_dependency_gen_args(self, outtarget, outfile): return ['-MMD', '-MQ', outtarget, '-MF', outfile] + def depfile_for_object(self, objfile): + return objfile + '.' + self.get_depfile_suffix() + def get_depfile_suffix(self): return 'd' @@ -985,6 +988,9 @@ class SwiftCompiler(Compiler): def get_dependency_gen_args(self, outtarget, outfile): return ['-emit-dependencies'] + def depfile_for_object(self, objfile): + return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix() + def get_depfile_suffix(self): return 'd' @@ -1562,6 +1568,9 @@ end program prog def get_module_outdir_args(self, path): return ['-J' + path] + def depfile_for_object(self, objfile): + return objfile + '.' + self.get_depfile_suffix() + def get_depfile_suffix(self): return 'd' diff --git a/ninjabackend.py b/ninjabackend.py index 7d72e0672..c8134d7a1 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -1269,7 +1269,7 @@ rule FORTRAN_DEP_HACK obj_basename = src_filename.replace('/', '_').replace('\\', '_') rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) rel_obj += '.' + self.environment.get_object_suffix() - dep_file = rel_obj + '.' + compiler.get_depfile_suffix() + dep_file = compiler.depfile_for_object(rel_obj) if self.environment.coredata.get_builtin_option('use_pch'): pchlist = target.get_pch(compiler.language) else: -- cgit v1.2.3 From 43b07729aa058ce8af1aa4d7f3c445f61f39c42a Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Thu, 10 Dec 2015 21:49:41 +0200 Subject: Reworked swift code so now can use multiple source files in one target. --- backends.py | 20 +++++------ compilers.py | 3 ++ dirchanger.py | 24 +++++++++++++ ninjabackend.py | 58 +++++++++++++++++++++++++++++- test cases/swift/2 multifile/libfile.swift | 3 ++ test cases/swift/2 multifile/main.swift | 1 + test cases/swift/2 multifile/meson.build | 3 ++ 7 files changed, 101 insertions(+), 11 deletions(-) create mode 100755 dirchanger.py create mode 100644 test cases/swift/2 multifile/libfile.swift create mode 100644 test cases/swift/2 multifile/main.swift create mode 100644 test cases/swift/2 multifile/meson.build diff --git a/backends.py b/backends.py index 03ecd4b29..70b206af3 100644 --- a/backends.py +++ b/backends.py @@ -132,23 +132,23 @@ class Backend(): self.write_benchmark_file(datafile) datafile.close() - def has_vala(self, target): + def has_source_suffix(self, target, suffix): for s in target.get_sources(): - if s.endswith('.vala'): + if s.endswith(suffix): return True return False + def has_vala(self, target): + return self.has_source_suffix(target, '.vala') + def has_rust(self, target): - for s in target.get_sources(): - if s.endswith('.rs'): - return True - return False + return self.has_source_suffix(target, '.rs') def has_cs(self, target): - for s in target.get_sources(): - if s.endswith('.cs'): - return True - return False + return self.has_source_suffix(target, '.cs') + + def has_swift(self, target): + return self.has_source_suffix(target, '.swift') def determine_linker(self, target, src): if isinstance(target, build.StaticLibrary): diff --git a/compilers.py b/compilers.py index 41c4ecd29..c496a5d5a 100644 --- a/compilers.py +++ b/compilers.py @@ -1012,6 +1012,9 @@ class SwiftCompiler(Compiler): def get_std_exe_link_args(self): return ['-emit-executable'] + def get_module_args(self, modname): + return ['-module-name', modname] + def build_rpath_args(self, *args): return [] # FIXME diff --git a/dirchanger.py b/dirchanger.py new file mode 100755 index 000000000..4cc863adb --- /dev/null +++ b/dirchanger.py @@ -0,0 +1,24 @@ +# Copyright 2015 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +'''CD into dir given as first argument and execute +the command given in the rest of the arguments.''' + +import os, subprocess, sys + +dirname = sys.argv[1] +command = sys.argv[2:] + +os.chdir(dirname) +sys.exit(subprocess.call(command)) diff --git a/ninjabackend.py b/ninjabackend.py index c8134d7a1..9a8aa0bf3 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -195,6 +195,9 @@ class NinjaBackend(backends.Backend): return if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target): gen_src_deps += self.generate_vala_compile(target, outfile) + if 'swift' in self.environment.coredata.compilers.keys() and self.has_swift(target): + self.generate_swift_target(target, outfile) + return self.scan_fortran_module_outputs(target) # The following deals with C/C++ compilation. (gen_src, gen_other_deps) = self.process_dep_gens(outfile, target) @@ -834,6 +837,42 @@ class NinjaBackend(backends.Backend): element.write(outfile) self.check_outputs(element) + def generate_swift_target(self, target, outfile): + swiftc = self.environment.coredata.compilers['swift'] + abssrc = [] + for i in target.get_sources(): + if not swiftc.can_compile(i): + raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename()) + relsrc = i.rel_to_builddir(self.build_to_src) + abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc)) + abssrc.append(abss) + os.makedirs(os.path.join(self.get_target_private_dir_abs(target)), exist_ok=True) + # We need absolute paths because swiftc needs to be invoked in a subdir + # and this is the easiest way about it. + objects = [] # Relative to swift invocation dir + rel_objects = [] # Relative to build.ninja + for i in abssrc: + base = os.path.split(i)[1] + oname = os.path.splitext(base)[0] + '.o' + objects.append(oname) + rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) + compile_args = swiftc.get_compile_only_args() + compile_args += swiftc.get_module_args(target.name) + link_args = swiftc.get_output_args(self.get_target_filename(target)) + rundir = self.get_target_private_dir(target) + + elem = NinjaBuildElement(rel_objects, 'swift_COMPILER', abssrc) + elem.add_item('ARGS', compile_args) + elem.add_item('RUNDIR', rundir) + elem.write(outfile) + self.check_outputs(elem) + elem = NinjaBuildElement(self.get_target_filename(target), 'swift_COMPILER', []) + elem.add_dep(rel_objects) + elem.add_item('ARGS', link_args + objects) + elem.add_item('RUNDIR', rundir) + elem.write(outfile) + self.check_outputs(elem) + def generate_static_link_rules(self, is_cross, outfile): if self.build.has_language('java'): if not is_cross: @@ -958,7 +997,10 @@ class NinjaBackend(backends.Backend): def generate_rust_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) + full_exe = [sys.executable, + os.path.join(self.environment.get_script_root(), 'dirchanger'), + '$RUNDIR'] + compiler.get_exelist() + invoc = ' '.join([ninja_quote(i) for i in full_exe]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Rust source $in.\n' depfile = ' depfile = $targetdep\n' @@ -971,6 +1013,16 @@ class NinjaBackend(backends.Backend): outfile.write(depstyle) outfile.write('\n') + def generate_swift_compile_rules(self, compiler, outfile): + rule = 'rule %s_COMPILER\n' % compiler.get_language() + invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) + command = ' command = %s $ARGS $in\n' % invoc + description = ' description = Compiling Swift source $in.\n' + outfile.write(rule) + outfile.write(command) + outfile.write(description) + outfile.write('\n') + def generate_fortran_dep_hack(self, outfile): if mesonlib.is_windows(): cmd = 'cmd /C ""' @@ -1004,6 +1056,10 @@ rule FORTRAN_DEP_HACK if not is_cross: self.generate_rust_compile_rules(compiler, outfile) return + if langname == 'swift': + if not is_cross: + self.generate_swift_compile_rules(compiler, outfile) + return if langname == 'fortran': self.generate_fortran_dep_hack(outfile) if is_cross: diff --git a/test cases/swift/2 multifile/libfile.swift b/test cases/swift/2 multifile/libfile.swift new file mode 100644 index 000000000..45f941ca7 --- /dev/null +++ b/test cases/swift/2 multifile/libfile.swift @@ -0,0 +1,3 @@ +func printSomething(text: String) { + print("Got this: \(text)") +} diff --git a/test cases/swift/2 multifile/main.swift b/test cases/swift/2 multifile/main.swift new file mode 100644 index 000000000..61d67e2fb --- /dev/null +++ b/test cases/swift/2 multifile/main.swift @@ -0,0 +1 @@ +printSomething("String from main") diff --git a/test cases/swift/2 multifile/meson.build b/test cases/swift/2 multifile/meson.build new file mode 100644 index 000000000..9012f3d41 --- /dev/null +++ b/test cases/swift/2 multifile/meson.build @@ -0,0 +1,3 @@ +project('2 files', 'swift') + +test('2files', executable('twofiles', 'main.swift', 'libfile.swift')) -- cgit v1.2.3 From d531f915b12ad648c1ae08749548233882087f12 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 11 Dec 2015 00:19:25 +0200 Subject: Can build Swift libraries and link them. --- backends.py | 7 +++ compilers.py | 3 + ninjabackend.py | 80 ++++++++++++++++++++---- test cases/swift/3 library/exe/main.swift | 7 +++ test cases/swift/3 library/exe/meson.build | 2 + test cases/swift/3 library/lib/datasource.swift | 3 + test cases/swift/3 library/lib/meson.build | 1 + test cases/swift/3 library/lib/othersource.swift | 3 + test cases/swift/3 library/meson.build | 4 ++ 9 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 test cases/swift/3 library/exe/main.swift create mode 100644 test cases/swift/3 library/exe/meson.build create mode 100644 test cases/swift/3 library/lib/datasource.swift create mode 100644 test cases/swift/3 library/lib/meson.build create mode 100644 test cases/swift/3 library/lib/othersource.swift create mode 100644 test cases/swift/3 library/meson.build diff --git a/backends.py b/backends.py index 70b206af3..754389499 100644 --- a/backends.py +++ b/backends.py @@ -83,6 +83,13 @@ class Backend(): os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname + # Crap hack. The above was doing the wrong thing but too many thing use it to fix + # now. Get fixed once Swift works. + def get_target_private_dir_abs_v2(self, target): + dirname = os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target)) + os.makedirs(dirname, exist_ok=True) + return dirname + def generate_unity_files(self, target, unity_src): langlist = {} abs_files = [] diff --git a/compilers.py b/compilers.py index c496a5d5a..ed8d4fb4b 100644 --- a/compilers.py +++ b/compilers.py @@ -1015,6 +1015,9 @@ class SwiftCompiler(Compiler): def get_module_args(self, modname): return ['-module-name', modname] + def get_mod_gen_args(self): + return ['-emit-module'] + def build_rpath_args(self, *args): return [] # FIXME diff --git a/ninjabackend.py b/ninjabackend.py index 9a8aa0bf3..2230b1f5c 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -837,7 +837,33 @@ class NinjaBackend(backends.Backend): element.write(outfile) self.check_outputs(element) + def swift_module_file_name(self, target): + return os.path.join(self.get_target_private_dir(target), + self.target_swift_modulename(target) + '.swiftmodule') + + def target_swift_modulename(self, target): + return target.name + + def determine_swift_dep_modules(self, target): + result = [] + for l in target.link_targets: + result.append(self.swift_module_file_name(l)) + return result + + def determine_swift_dep_dirs(self, target): + result = [] + for l in target.link_targets: + result.append(self.get_target_private_dir_abs_v2(l)) + return result + + def get_swift_link_deps(self, target): + result = [] + for l in target.link_targets: + result.append(self.get_target_filename(l)) + return result + def generate_swift_target(self, target, outfile): + module_name = self.target_swift_modulename(target) swiftc = self.environment.coredata.compilers['swift'] abssrc = [] for i in target.get_sources(): @@ -857,21 +883,49 @@ class NinjaBackend(backends.Backend): objects.append(oname) rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) compile_args = swiftc.get_compile_only_args() - compile_args += swiftc.get_module_args(target.name) - link_args = swiftc.get_output_args(self.get_target_filename(target)) + compile_args += swiftc.get_module_args(module_name) + link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) rundir = self.get_target_private_dir(target) - - elem = NinjaBuildElement(rel_objects, 'swift_COMPILER', abssrc) - elem.add_item('ARGS', compile_args) + out_module_name = self.swift_module_file_name(target) + in_module_files = self.determine_swift_dep_modules(target) + abs_module_dirs = self.determine_swift_dep_dirs(target) + module_includes = [] + for x in abs_module_dirs: + module_includes += swiftc.get_include_args(x) + link_deps = self.get_swift_link_deps(target) + abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps] + + # Swiftc does not seem to be able to emit objects and module files in one go. + elem = NinjaBuildElement(rel_objects, + 'swift_COMPILER', + abssrc) + elem.add_dep(in_module_files) + elem.add_item('ARGS', compile_args + module_includes) elem.add_item('RUNDIR', rundir) elem.write(outfile) self.check_outputs(elem) - elem = NinjaBuildElement(self.get_target_filename(target), 'swift_COMPILER', []) - elem.add_dep(rel_objects) - elem.add_item('ARGS', link_args + objects) + elem = NinjaBuildElement(out_module_name, + 'swift_COMPILER', + abssrc) + elem.add_dep(in_module_files) + elem.add_item('ARGS', compile_args + module_includes + swiftc.get_mod_gen_args()) elem.add_item('RUNDIR', rundir) elem.write(outfile) self.check_outputs(elem) + if isinstance(target, build.StaticLibrary): + elem = self.generate_link(target, outfile, self.get_target_filename(target), + rel_objects, self.build.static_linker) + elem.write(outfile) + elif isinstance(target, build.Executable): + elem = NinjaBuildElement(self.get_target_filename(target), 'swift_COMPILER', []) + elem.add_dep(rel_objects) + elem.add_dep(link_deps) + elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps) + elem.add_item('RUNDIR', rundir) + elem.write(outfile) + self.check_outputs(elem) + else: + raise MesonException('Swift supports only executable and static library targets.') def generate_static_link_rules(self, is_cross, outfile): if self.build.has_language('java'): @@ -997,10 +1051,7 @@ class NinjaBackend(backends.Backend): def generate_rust_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() - full_exe = [sys.executable, - os.path.join(self.environment.get_script_root(), 'dirchanger'), - '$RUNDIR'] + compiler.get_exelist() - invoc = ' '.join([ninja_quote(i) for i in full_exe]) + invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Rust source $in.\n' depfile = ' depfile = $targetdep\n' @@ -1015,7 +1066,10 @@ class NinjaBackend(backends.Backend): def generate_swift_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) + full_exe = [sys.executable, + os.path.join(self.environment.get_script_dir(), 'dirchanger.py'), + '$RUNDIR'] + compiler.get_exelist() + invoc = ' '.join([ninja_quote(i) for i in full_exe]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Swift source $in.\n' outfile.write(rule) diff --git a/test cases/swift/3 library/exe/main.swift b/test cases/swift/3 library/exe/main.swift new file mode 100644 index 000000000..c5de3739b --- /dev/null +++ b/test cases/swift/3 library/exe/main.swift @@ -0,0 +1,7 @@ +import DataSource + +let data = getData() +let data2 = getOther() + +print("String from module: \(data)") +print("Other string: \(data2)") diff --git a/test cases/swift/3 library/exe/meson.build b/test cases/swift/3 library/exe/meson.build new file mode 100644 index 000000000..6c13957e5 --- /dev/null +++ b/test cases/swift/3 library/exe/meson.build @@ -0,0 +1,2 @@ +exe = executable('dataprog', 'main.swift', link_with : datasource) +test('dataprog', exe) diff --git a/test cases/swift/3 library/lib/datasource.swift b/test cases/swift/3 library/lib/datasource.swift new file mode 100644 index 000000000..4ac7c2ab8 --- /dev/null +++ b/test cases/swift/3 library/lib/datasource.swift @@ -0,0 +1,3 @@ +public func getData() -> String { + return "String from module." +} diff --git a/test cases/swift/3 library/lib/meson.build b/test cases/swift/3 library/lib/meson.build new file mode 100644 index 000000000..fc65556d8 --- /dev/null +++ b/test cases/swift/3 library/lib/meson.build @@ -0,0 +1 @@ +datasource = static_library('DataSource', 'datasource.swift', 'othersource.swift') diff --git a/test cases/swift/3 library/lib/othersource.swift b/test cases/swift/3 library/lib/othersource.swift new file mode 100644 index 000000000..fb668baa5 --- /dev/null +++ b/test cases/swift/3 library/lib/othersource.swift @@ -0,0 +1,3 @@ +public func getOther() -> String { + return "String from other source." +} diff --git a/test cases/swift/3 library/meson.build b/test cases/swift/3 library/meson.build new file mode 100644 index 000000000..d601721f0 --- /dev/null +++ b/test cases/swift/3 library/meson.build @@ -0,0 +1,4 @@ +project('linking', 'swift') + +subdir('lib') +subdir('exe') -- cgit v1.2.3 From 961b000090e01a1eb3647c6b16d951ca419b13cb Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 11 Dec 2015 23:14:16 +0200 Subject: Can generate swift sources with custom target. --- ninjabackend.py | 48 ++++++++++++++++++++-------- test cases/swift/4 generate/gen/main.swift | 10 ++++++ test cases/swift/4 generate/gen/meson.build | 6 ++++ test cases/swift/4 generate/meson.build | 4 +++ test cases/swift/4 generate/user/main.swift | 3 ++ test cases/swift/4 generate/user/meson.build | 2 ++ 6 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 test cases/swift/4 generate/gen/main.swift create mode 100644 test cases/swift/4 generate/gen/meson.build create mode 100644 test cases/swift/4 generate/meson.build create mode 100644 test cases/swift/4 generate/user/main.swift create mode 100644 test cases/swift/4 generate/user/meson.build diff --git a/ninjabackend.py b/ninjabackend.py index 2230b1f5c..b91250cd6 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -862,6 +862,26 @@ class NinjaBackend(backends.Backend): result.append(self.get_target_filename(l)) return result + def split_swift_generated_sources(self, target): + all_srcs = [] + for genlist in target.get_generated_sources(): + if isinstance(genlist, build.CustomTarget): + for ifile in genlist.get_filename(): + rel = os.path.join(self.get_target_dir(genlist), ifile) + all_srcs.append(rel) + else: + for ifile in genlist.get_outfilelist(): + rel = os.path.join(self.get_target_private_dir(target), ifile) + all_srcs.append(rel) + srcs = [] + others = [] + for i in all_srcs: + if i.endswith('.swift'): + srcs.append(i) + else: + others.append(i) + return (srcs, others) + def generate_swift_target(self, target, outfile): module_name = self.target_swift_modulename(target) swiftc = self.environment.coredata.compilers['swift'] @@ -873,15 +893,6 @@ class NinjaBackend(backends.Backend): abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc)) abssrc.append(abss) os.makedirs(os.path.join(self.get_target_private_dir_abs(target)), exist_ok=True) - # We need absolute paths because swiftc needs to be invoked in a subdir - # and this is the easiest way about it. - objects = [] # Relative to swift invocation dir - rel_objects = [] # Relative to build.ninja - for i in abssrc: - base = os.path.split(i)[1] - oname = os.path.splitext(base)[0] + '.o' - objects.append(oname) - rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) compile_args = swiftc.get_compile_only_args() compile_args += swiftc.get_module_args(module_name) link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) @@ -894,21 +905,32 @@ class NinjaBackend(backends.Backend): module_includes += swiftc.get_include_args(x) link_deps = self.get_swift_link_deps(target) abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps] + (rel_generated, _) = self.split_swift_generated_sources(target) + abs_generated = [os.path.join(self.environment.get_build_dir(), x) for x in rel_generated] + # We need absolute paths because swiftc needs to be invoked in a subdir + # and this is the easiest way about it. + objects = [] # Relative to swift invocation dir + rel_objects = [] # Relative to build.ninja + for i in abssrc + abs_generated: + base = os.path.split(i)[1] + oname = os.path.splitext(base)[0] + '.o' + objects.append(oname) + rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) # Swiftc does not seem to be able to emit objects and module files in one go. elem = NinjaBuildElement(rel_objects, 'swift_COMPILER', abssrc) - elem.add_dep(in_module_files) - elem.add_item('ARGS', compile_args + module_includes) + elem.add_dep(in_module_files + rel_generated) + elem.add_item('ARGS', compile_args + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) elem.write(outfile) self.check_outputs(elem) elem = NinjaBuildElement(out_module_name, 'swift_COMPILER', abssrc) - elem.add_dep(in_module_files) - elem.add_item('ARGS', compile_args + module_includes + swiftc.get_mod_gen_args()) + elem.add_dep(in_module_files + rel_generated) + elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) elem.add_item('RUNDIR', rundir) elem.write(outfile) self.check_outputs(elem) diff --git a/test cases/swift/4 generate/gen/main.swift b/test cases/swift/4 generate/gen/main.swift new file mode 100644 index 000000000..2f2bd3683 --- /dev/null +++ b/test cases/swift/4 generate/gen/main.swift @@ -0,0 +1,10 @@ +import Glibc + +let fname = Process.arguments[1] +let code = "public func getGenerated() -> Int {\n return 42\n}\n" + +let f = fopen(fname, "w") + +fwrite(code, 1, Int(strlen(code)), f) +print("Name: \(fname)") +fclose(f) diff --git a/test cases/swift/4 generate/gen/meson.build b/test cases/swift/4 generate/gen/meson.build new file mode 100644 index 000000000..8cd7e0463 --- /dev/null +++ b/test cases/swift/4 generate/gen/meson.build @@ -0,0 +1,6 @@ +gen = executable('gen', 'main.swift') + +srcs = custom_target('gensrc', + output : 'gen.swift', + command : [gen, '@OUTPUT@'] +) diff --git a/test cases/swift/4 generate/meson.build b/test cases/swift/4 generate/meson.build new file mode 100644 index 000000000..ccc7d5c82 --- /dev/null +++ b/test cases/swift/4 generate/meson.build @@ -0,0 +1,4 @@ +project('swift generator', 'swift') + +subdir('gen') +subdir('user') diff --git a/test cases/swift/4 generate/user/main.swift b/test cases/swift/4 generate/user/main.swift new file mode 100644 index 000000000..e6b46cd19 --- /dev/null +++ b/test cases/swift/4 generate/user/main.swift @@ -0,0 +1,3 @@ +let generated = getGenerated() + +print("Generated number is: \(generated).") diff --git a/test cases/swift/4 generate/user/meson.build b/test cases/swift/4 generate/user/meson.build new file mode 100644 index 000000000..fc4722d4c --- /dev/null +++ b/test cases/swift/4 generate/user/meson.build @@ -0,0 +1,2 @@ +user = executable('user', 'main.swift', srcs) +test('User test', user) -- cgit v1.2.3 From 161d633f362a316e4711b8ab524d3688cd6847ef Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 12 Dec 2015 00:17:44 +0200 Subject: Added support for calling into C. --- compilers.py | 3 +++ ninjabackend.py | 28 ++++++++++++++++++++++------ test cases/swift/5 mixed/main.swift | 3 +++ test cases/swift/5 mixed/meson.build | 6 ++++++ test cases/swift/5 mixed/mylib.c | 5 +++++ test cases/swift/5 mixed/mylib.h | 3 +++ 6 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 test cases/swift/5 mixed/main.swift create mode 100644 test cases/swift/5 mixed/meson.build create mode 100644 test cases/swift/5 mixed/mylib.c create mode 100644 test cases/swift/5 mixed/mylib.h diff --git a/compilers.py b/compilers.py index ed8d4fb4b..0567764e9 100644 --- a/compilers.py +++ b/compilers.py @@ -1000,6 +1000,9 @@ class SwiftCompiler(Compiler): def get_linker_output_args(self, target): return ['-o', target] + def get_header_import_args(self, headername): + return ['-import-objc-header', headername] + def get_warn_args(self, level): return [] diff --git a/ninjabackend.py b/ninjabackend.py index b91250cd6..1258f0714 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -844,10 +844,17 @@ class NinjaBackend(backends.Backend): def target_swift_modulename(self, target): return target.name + def is_swift_target(self, target): + for s in target.sources: + if s.endswith('swift'): + return True + return False + def determine_swift_dep_modules(self, target): result = [] for l in target.link_targets: - result.append(self.swift_module_file_name(l)) + if self.is_swift_target(l): + result.append(self.swift_module_file_name(l)) return result def determine_swift_dep_dirs(self, target): @@ -886,12 +893,20 @@ class NinjaBackend(backends.Backend): module_name = self.target_swift_modulename(target) swiftc = self.environment.coredata.compilers['swift'] abssrc = [] + abs_headers = [] + header_imports = [] for i in target.get_sources(): - if not swiftc.can_compile(i): + if swiftc.can_compile(i): + relsrc = i.rel_to_builddir(self.build_to_src) + abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc)) + abssrc.append(abss) + elif self.environment.is_header(i): + relh = i.rel_to_builddir(self.build_to_src) + absh = os.path.normpath(os.path.join(self.environment.get_build_dir(), relh)) + abs_headers.append(absh) + header_imports += swiftc.get_header_import_args(absh) + else: raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename()) - relsrc = i.rel_to_builddir(self.build_to_src) - abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc)) - abssrc.append(abss) os.makedirs(os.path.join(self.get_target_private_dir_abs(target)), exist_ok=True) compile_args = swiftc.get_compile_only_args() compile_args += swiftc.get_module_args(module_name) @@ -922,7 +937,8 @@ class NinjaBackend(backends.Backend): 'swift_COMPILER', abssrc) elem.add_dep(in_module_files + rel_generated) - elem.add_item('ARGS', compile_args + abs_generated + module_includes) + elem.add_dep(abs_headers) + elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) elem.write(outfile) self.check_outputs(elem) diff --git a/test cases/swift/5 mixed/main.swift b/test cases/swift/5 mixed/main.swift new file mode 100644 index 000000000..557412687 --- /dev/null +++ b/test cases/swift/5 mixed/main.swift @@ -0,0 +1,3 @@ +let num = getNumber() + +print("The number returned from C code is: \(num).") diff --git a/test cases/swift/5 mixed/meson.build b/test cases/swift/5 mixed/meson.build new file mode 100644 index 000000000..71cb99d52 --- /dev/null +++ b/test cases/swift/5 mixed/meson.build @@ -0,0 +1,6 @@ +project('mixed', 'c', 'swift') + +lib = static_library('mylib', 'mylib.c') +exe = executable('prog', 'main.swift', 'mylib.h', + link_with : lib) +test('c interface', exe) diff --git a/test cases/swift/5 mixed/mylib.c b/test cases/swift/5 mixed/mylib.c new file mode 100644 index 000000000..e091836bc --- /dev/null +++ b/test cases/swift/5 mixed/mylib.c @@ -0,0 +1,5 @@ +#include"mylib.h" + +int getNumber() { + return 42; +} diff --git a/test cases/swift/5 mixed/mylib.h b/test cases/swift/5 mixed/mylib.h new file mode 100644 index 000000000..21bd9eb0b --- /dev/null +++ b/test cases/swift/5 mixed/mylib.h @@ -0,0 +1,3 @@ +#pragma once + +int getNumber(); -- cgit v1.2.3