From 7e1df7540d519f63b4309b380e69b10ca5bff103 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 26 Dec 2015 20:28:23 +0200 Subject: [PATCH 1/2] Handle custom targets that produce static libraries that are then linked to other targets. --- backends.py | 3 + compilers.py | 7 +++ environment.py | 3 + ninjabackend.py | 16 ++++- test cases/common/103 manygen/depuser.c | 8 +++ test cases/common/103 manygen/funcinfo.def | 1 + test cases/common/103 manygen/manygen.py | 69 ++++++++++++++++++++++ test cases/common/103 manygen/meson.build | 14 +++++ 8 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 test cases/common/103 manygen/depuser.c create mode 100644 test cases/common/103 manygen/funcinfo.def create mode 100755 test cases/common/103 manygen/manygen.py create mode 100644 test cases/common/103 manygen/meson.build diff --git a/backends.py b/backends.py index c996cb8eb..64d386033 100644 --- a/backends.py +++ b/backends.py @@ -358,6 +358,9 @@ class Backend(): ofilenames = [os.path.join(self.get_target_dir(target), i) for i in target.output] srcs = [] outdir = self.get_target_dir(target) + # Many external programs fail on empty arguments. + if outdir == '': + outdir = '.' if absolute_paths: outdir = os.path.join(self.environment.get_build_dir(), outdir) for i in target.sources: diff --git a/compilers.py b/compilers.py index 06dd1d049..73fd8cd57 100644 --- a/compilers.py +++ b/compilers.py @@ -28,6 +28,7 @@ cpp_suffixes = ['cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'hxx', 'c++'] c_suffixes = ['c'] clike_suffixes = c_suffixes + cpp_suffixes obj_suffixes = ['o', 'obj', 'res'] +lib_suffixes = ['a', 'lib', 'dll', 'dylib', 'so'] def is_header(fname): if hasattr(fname, 'fname'): @@ -47,6 +48,12 @@ def is_object(fname): suffix = fname.split('.')[-1] return suffix in obj_suffixes +def is_library(fname): + if hasattr(fname, 'fname'): + fname = fname.fname + suffix = fname.split('.')[-1] + return suffix in lib_suffixes + gnulike_buildtype_args = {'plain' : [], 'debug' : ['-g'], 'debugoptimized' : ['-O2', '-g'], diff --git a/environment.py b/environment.py index e09f6ae36..e905b2fac 100644 --- a/environment.py +++ b/environment.py @@ -145,6 +145,9 @@ class Environment(): def is_object(self, fname): return is_object(fname) + def is_library(self, fname): + return is_library(fname) + def merge_options(self, options): for (name, value) in options.items(): if name not in self.coredata.user_options: diff --git a/ninjabackend.py b/ninjabackend.py index c465f7cbb..5b75bce10 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -264,6 +264,8 @@ int dummy; header_deps)) elif self.environment.is_object(src): obj_list.append(src) + elif self.environment.is_library(src): + pass else: # Assume anything not specifically a source file is a header. This is because # people generate files with weird suffixes (.inc, .fh) that they then include @@ -1674,17 +1676,29 @@ rule FORTRAN_DEP_HACK self.determine_rpath_dirs(target), target.install_rpath) if self.environment.coredata.get_builtin_option('coverage'): commands += linker.get_coverage_link_args() + custom_target_libraries = self.get_custom_target_provided_libraries(target) commands += extra_args + commands += custom_target_libraries commands = linker.unixtype_flags_to_native(commands) dep_targets = [self.get_dependency_filename(t) for t in dependencies] dep_targets += [os.path.join(self.environment.source_dir, target.subdir, t) for t in target.link_depends] elem = NinjaBuildElement(outname, linker_rule, obj_list) - elem.add_dep(dep_targets) + elem.add_dep(dep_targets + custom_target_libraries) elem.add_item('LINK_ARGS', commands) self.check_outputs(elem) return elem + def get_custom_target_provided_libraries(self, target): + libs = [] + for t in target.get_generated_sources(): + if not isinstance(t, build.CustomTarget): + continue + for f in t.output: + if self.environment.is_library(f): + libs.append(os.path.join(self.get_target_dir(target), f)) + return libs + def determine_rpath_dirs(self, target): link_deps = target.get_all_link_deps() result = [] diff --git a/test cases/common/103 manygen/depuser.c b/test cases/common/103 manygen/depuser.c new file mode 100644 index 000000000..1a825e0ec --- /dev/null +++ b/test cases/common/103 manygen/depuser.c @@ -0,0 +1,8 @@ +#include"gen_func.h" + +int main(int argc, char **argv) { + unsigned int i = (unsigned int) gen_func_in_lib(); + unsigned int j = (unsigned int) gen_func_in_obj(); + unsigned int k = (unsigned int) gen_func_in_src(); + return (int)(i + j + k); +} diff --git a/test cases/common/103 manygen/funcinfo.def b/test cases/common/103 manygen/funcinfo.def new file mode 100644 index 000000000..b0741862e --- /dev/null +++ b/test cases/common/103 manygen/funcinfo.def @@ -0,0 +1 @@ +gen_func diff --git a/test cases/common/103 manygen/manygen.py b/test cases/common/103 manygen/manygen.py new file mode 100755 index 000000000..fbf2eae40 --- /dev/null +++ b/test cases/common/103 manygen/manygen.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +# Generates a static library, object file, source +# file and a header file. + +import sys, os +import shutil, subprocess + +funcname = open(sys.argv[1]).readline().strip() +outdir = sys.argv[2] + +if not os.path.isdir(outdir): + print('Outdir does not exist.') + sys.exit(1) + +if shutil.which('cl'): + print('VS support not yet added.') + sys.exit(1) + +objsuffix = '.o' +libsuffix = '.a' + +outo = os.path.join(outdir, funcname + objsuffix) +outa = os.path.join(outdir, funcname + libsuffix) +outh = os.path.join(outdir, funcname + '.h') +outc = os.path.join(outdir, funcname + '.c') + +compiler = shutil.which('gcc') +if compiler is None: + compiler = shutil.which('clang') +if compiler is None: + compiler = shutil.which('cc') +if compiler is None: + print('No known compilers found.') + sys.exit(1) +linker = 'ar' + +tmpc = 'diibadaaba.c' +tmpo = 'diibadaaba' + objsuffix + +open(outc, 'w').write('''#include"%s.h" +int %s_in_src() { + return 0; +} +''' % (funcname, funcname)) + +open(outh, 'w').write('''#pragma once +int %s_in_lib(); +int %s_in_obj(); +int %s_in_src(); +''' % (funcname, funcname, funcname)) + +open(tmpc, 'w').write('''int %s_in_obj() { + return 0; +} +''' % funcname) + +subprocess.check_call([compiler, '-c', '-o', outo, tmpc]) + +open(tmpc, 'w').write('''int %s_in_lib() { + return 0; +} +''' % funcname) + +subprocess.check_call([compiler, '-c', '-o', tmpo, tmpc]) +subprocess.check_call([linker, 'csr', outa, tmpo]) +os.unlink(tmpo) +os.unlink(tmpc) + diff --git a/test cases/common/103 manygen/meson.build b/test cases/common/103 manygen/meson.build new file mode 100644 index 000000000..6079bc4d3 --- /dev/null +++ b/test cases/common/103 manygen/meson.build @@ -0,0 +1,14 @@ +project('manygen', 'c') + +gen = find_program('manygen.py') + +generated = custom_target('manygen', + output : ['gen_func.a', 'gen_func.c', 'gen_func.h', 'gen_func.o'], + input : ['funcinfo.def'], + command : [gen, '@INPUT@', '@OUTDIR@'], +) + +exe = executable('depuser', 'depuser.c', + generated) + +test('depuser test', exe) From 9bf641e545f163cd5e9e7e3b5e9aa1f9e002e5d9 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 27 Dec 2015 19:27:05 +0200 Subject: [PATCH 2/2] Fix path generation so generations in subdirs work. --- ninjabackend.py | 2 +- test cases/common/103 manygen/meson.build | 8 +------- test cases/common/103 manygen/{ => subdir}/funcinfo.def | 0 test cases/common/103 manygen/{ => subdir}/manygen.py | 0 test cases/common/103 manygen/subdir/meson.build | 7 +++++++ 5 files changed, 9 insertions(+), 8 deletions(-) rename test cases/common/103 manygen/{ => subdir}/funcinfo.def (100%) rename test cases/common/103 manygen/{ => subdir}/manygen.py (100%) create mode 100644 test cases/common/103 manygen/subdir/meson.build diff --git a/ninjabackend.py b/ninjabackend.py index 5b75bce10..8fc17720f 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -1696,7 +1696,7 @@ rule FORTRAN_DEP_HACK continue for f in t.output: if self.environment.is_library(f): - libs.append(os.path.join(self.get_target_dir(target), f)) + libs.append(os.path.join(self.get_target_dir(t), f)) return libs def determine_rpath_dirs(self, target): diff --git a/test cases/common/103 manygen/meson.build b/test cases/common/103 manygen/meson.build index 6079bc4d3..5079d1b82 100644 --- a/test cases/common/103 manygen/meson.build +++ b/test cases/common/103 manygen/meson.build @@ -1,12 +1,6 @@ project('manygen', 'c') -gen = find_program('manygen.py') - -generated = custom_target('manygen', - output : ['gen_func.a', 'gen_func.c', 'gen_func.h', 'gen_func.o'], - input : ['funcinfo.def'], - command : [gen, '@INPUT@', '@OUTDIR@'], -) +subdir('subdir') exe = executable('depuser', 'depuser.c', generated) diff --git a/test cases/common/103 manygen/funcinfo.def b/test cases/common/103 manygen/subdir/funcinfo.def similarity index 100% rename from test cases/common/103 manygen/funcinfo.def rename to test cases/common/103 manygen/subdir/funcinfo.def diff --git a/test cases/common/103 manygen/manygen.py b/test cases/common/103 manygen/subdir/manygen.py similarity index 100% rename from test cases/common/103 manygen/manygen.py rename to test cases/common/103 manygen/subdir/manygen.py diff --git a/test cases/common/103 manygen/subdir/meson.build b/test cases/common/103 manygen/subdir/meson.build new file mode 100644 index 000000000..4470d1a17 --- /dev/null +++ b/test cases/common/103 manygen/subdir/meson.build @@ -0,0 +1,7 @@ +gen = find_program('manygen.py') + +generated = custom_target('manygen', + output : ['gen_func.a', 'gen_func.c', 'gen_func.h', 'gen_func.o'], + input : ['funcinfo.def'], + command : [gen, '@INPUT@', '@OUTDIR@'], +)