aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2019-05-02 22:21:56 +0300
committerGitHub <noreply@github.com>2019-05-02 22:21:56 +0300
commit7059c47aad2ef28046ceb8566f0c1d2f98e03cb1 (patch)
tree01bdf4592080181fbd7c89f2350ae8573f8bb98a
parent70997ca969dab0de7a800af7f7c7d6c7e25cf4ac (diff)
parentd74ab216db4e4eb7574813517b5a7edb44631e1c (diff)
downloadmeson-7059c47aad2ef28046ceb8566f0c1d2f98e03cb1.zip
meson-7059c47aad2ef28046ceb8566f0c1d2f98e03cb1.tar.gz
meson-7059c47aad2ef28046ceb8566f0c1d2f98e03cb1.tar.bz2
Merge pull request #5161 from TheQwertiest/feature/custom_target_link
Can link against custom_target[i]
-rw-r--r--docs/markdown/snippets/linkcustom.md5
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/backend/vs2010backend.py16
-rw-r--r--mesonbuild/build.py32
-rw-r--r--test cases/common/216 link custom/meson.build22
-rw-r--r--test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py90
-rw-r--r--test cases/common/217 link custom_i single from multiple/meson.build37
-rw-r--r--test cases/common/217 link custom_i single from multiple/prog.c5
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py92
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/meson.build37
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/prog.c8
11 files changed, 336 insertions, 12 deletions
diff --git a/docs/markdown/snippets/linkcustom.md b/docs/markdown/snippets/linkcustom.md
index d6ee801..0cf45ad 100644
--- a/docs/markdown/snippets/linkcustom.md
+++ b/docs/markdown/snippets/linkcustom.md
@@ -1,6 +1,6 @@
## Can link against custom targets
-The output of `custom_target` can be used in `link_with` and
+The output of `custom_target` and `custom_target[i]` can be used in `link_with` and
`link_whole` keyword arguments. This is useful for integrating custom
code generator steps, but note that there are many limitations:
@@ -10,7 +10,8 @@ code generator steps, but note that there are many limitations:
- The user is responsible for ensuring that the code produced by
different toolchains are compatible.
- - The custom target can only have one output file.
+ - `custom_target` may only be used when it has a single output file.
+ Use `custom_target[i]` when dealing with multiple output files.
- The output file must have the correct file name extension.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 4a4f7f4..e40bcbc 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -171,6 +171,8 @@ class Backend:
mlog.warning('custom_target {!r} has more than one output! '
'Using the first one.'.format(t.name))
filename = t.get_outputs()[0]
+ elif isinstance(t, build.CustomTargetIndex):
+ filename = t.get_outputs()[0]
else:
assert(isinstance(t, build.BuildTarget))
filename = t.get_filename()
@@ -214,7 +216,7 @@ class Backend:
return os.path.join(self.get_target_dir(target), link_lib)
elif isinstance(target, build.StaticLibrary):
return os.path.join(self.get_target_dir(target), target.get_filename())
- elif isinstance(target, build.CustomTarget):
+ elif isinstance(target, (build.CustomTarget, build.CustomTargetIndex)):
if not target.is_linkable_target():
raise MesonException('Tried to link against custom target "%s", which is not linkable.' % target.name)
return os.path.join(self.get_target_dir(target), target.get_filename())
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index d1bf1e5..afbd59b 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -249,9 +249,15 @@ class Vs2010Backend(backends.Backend):
all_deps[d.get_id()] = d
elif isinstance(target, build.BuildTarget):
for ldep in target.link_targets:
- all_deps[ldep.get_id()] = ldep
+ if isinstance(ldep, build.CustomTargetIndex):
+ all_deps[ldep.get_id()] = ldep.target
+ else:
+ all_deps[ldep.get_id()] = ldep
for ldep in target.link_whole_targets:
- all_deps[ldep.get_id()] = ldep
+ if isinstance(ldep, build.CustomTargetIndex):
+ all_deps[ldep.get_id()] = ldep.target
+ else:
+ all_deps[ldep.get_id()] = ldep
for obj_id, objdep in self.get_obj_target_deps(target.objects):
all_deps[obj_id] = objdep
for gendep in target.get_generated_sources():
@@ -1111,7 +1117,11 @@ class Vs2010Backend(backends.Backend):
# Add more libraries to be linked if needed
for t in target.get_dependencies():
- lobj = self.build.targets[t.get_id()]
+ if isinstance(t, build.CustomTargetIndex):
+ # We don't need the actual project here, just the library name
+ lobj = t
+ else:
+ lobj = self.build.targets[t.get_id()]
linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
if t in target.link_whole_targets:
# /WHOLEARCHIVE:foo must go into AdditionalOptions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 4c8e50b..1fad9e0 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -576,7 +576,7 @@ class BuildTarget(Target):
if self.link_targets or self.link_whole_targets:
extra = set()
for t in itertools.chain(self.link_targets, self.link_whole_targets):
- if isinstance(t, CustomTarget):
+ if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex):
continue # We can't know anything about these.
for name, compiler in t.compilers.items():
if name in clink_langs:
@@ -1066,7 +1066,7 @@ You probably should put it in link_with instead.''')
def link(self, target):
for t in listify(target, unholder=True):
- if not isinstance(t, Target):
+ if not isinstance(t, (Target, CustomTargetIndex)):
raise InvalidArguments('{!r} is not a target.'.format(t))
if not t.is_linkable_target():
raise InvalidArguments('Link target {!r} is not linkable.'.format(t))
@@ -1074,13 +1074,13 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, CustomTarget) and self.is_cross != t.is_cross:
+ if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_targets.append(t)
def link_whole(self, target):
for t in listify(target, unholder=True):
- if isinstance(t, CustomTarget):
+ if isinstance(t, (CustomTarget, CustomTargetIndex)):
if not t.is_linkable_target():
raise InvalidArguments('Custom target {!r} is not linkable.'.format(t))
if not t.get_filename().endswith('.a'):
@@ -1091,7 +1091,7 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, CustomTarget) and self.is_cross != t.is_cross:
+ if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_whole_targets.append(t)
@@ -1168,7 +1168,7 @@ You probably should put it in link_with instead.''')
# Check if any of the internal libraries this target links to were
# written in this language
for link_target in itertools.chain(self.link_targets, self.link_whole_targets):
- if isinstance(link_target, CustomTarget):
+ if isinstance(link_target, (CustomTarget, CustomTargetIndex)):
continue
for language in link_target.compilers:
if language not in langs:
@@ -2259,6 +2259,26 @@ class CustomTargetIndex:
def get_subdir(self):
return self.target.get_subdir()
+ def get_filename(self):
+ return self.output
+
+ def get_id(self):
+ return self.target.get_id()
+
+ def get_all_link_deps(self):
+ return self.target.get_all_link_deps()
+
+ def get_link_deps_mapping(self, prefix, environment):
+ return self.target.get_link_deps_mapping(prefix, environment)
+
+ def get_link_dep_subdirs(self):
+ return self.target.get_link_dep_subdirs()
+
+ def is_linkable_target(self):
+ suf = os.path.splitext(self.output)[-1]
+ if suf == '.a' or suf == '.dll' or suf == '.lib' or suf == '.so':
+ return True
+
class ConfigureFile:
def __init__(self, subdir, sourcename, targetname, configuration_data):
diff --git a/test cases/common/216 link custom/meson.build b/test cases/common/216 link custom/meson.build
index 5af27cd..c8d3a6d 100644
--- a/test cases/common/216 link custom/meson.build
+++ b/test cases/common/216 link custom/meson.build
@@ -16,6 +16,8 @@ clib = custom_target('linkcustom',
'-o', '@OUTPUT@',
'--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+# custom_target tests
+
exe = executable('prog', 'prog.c', link_with: clib)
test('linkcustom', exe)
@@ -33,3 +35,23 @@ d2 = declare_dependency(link_whole: clib)
exe4 = executable('prog4', 'prog.c', dependencies: d2)
test('linkwhole2', exe2)
+
+# custom_target[i] tests
+
+exe_i = executable('prog_i', 'prog.c', link_with: clib[0])
+test('linkcustom', exe_i)
+
+d_i = declare_dependency(link_with: clib[0])
+
+exe2_i = executable('prog2_i', 'prog.c', dependencies: d_i)
+test('linkcustom2_i', exe2_i)
+
+# Link whole tests
+
+exe3_i = executable('prog3_i', 'prog.c', link_whole: clib[0])
+test('linkwhole', exe)
+
+d2_i = declare_dependency(link_whole: clib[0])
+
+exe4_i = executable('prog4_i', 'prog.c', dependencies: d2_i)
+test('linkwhole2_i', exe2_i)
diff --git a/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py b/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py
new file mode 100644
index 0000000..42d6631
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+
+import shutil, sys, subprocess, argparse, pathlib
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--private-dir', required=True)
+parser.add_argument('-o', nargs='+', required=True)
+parser.add_argument('cmparr', nargs='+')
+
+contents = ['''
+int flob() {
+ return 0;
+}
+''', '''
+int flob() {
+ return 1;
+}
+''']
+
+def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
+ if shutil.which('ar'):
+ static_linker = 'ar'
+ elif shutil.which('llvm-ar'):
+ static_linker = 'llvm-ar'
+ elif shutil.which('gcc-ar'):
+ static_linker = 'gcc-ar'
+ else:
+ sys.exit('Could not detect a static linker.')
+ o_file = c_file.with_suffix('.o')
+ compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker, 'csr', outfile, str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+
+def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
+ static_linker = 'lib'
+ o_file = c_file.with_suffix('.obj')
+ compile_cmd = compiler_array + ['/MDd',
+ '/nologo',
+ '/ZI',
+ '/Ob0',
+ '/Od',
+ '/c',
+ '/Fo' + str(o_file),
+ str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker,
+ '/nologo',
+ '/OUT:' + str(outfile),
+ str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+def generate_lib(outfiles, private_dir, compiler_array):
+ private_dir = pathlib.Path(private_dir)
+ if not private_dir.exists():
+ private_dir.mkdir()
+
+ for i, content in enumerate(contents):
+ c_file = private_dir / ('flob_' + str(i + 1) + '.c')
+ c_file.write_text(content)
+ outfile = outfiles[i]
+
+ cl_found = False
+ for cl_arg in compiler_array:
+ if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
+ ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ else:
+ cl_found = True
+ break
+ if not cl_found:
+ ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ return 0
+
+if __name__ == '__main__':
+ options = parser.parse_args()
+ sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
diff --git a/test cases/common/217 link custom_i single from multiple/meson.build b/test cases/common/217 link custom_i single from multiple/meson.build
new file mode 100644
index 0000000..eee1fe1
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/meson.build
@@ -0,0 +1,37 @@
+project('linkcustom', 'c')
+
+# This would require passing the static linker to the build script or having
+# it detect it by itself. I'm too lazy to implement it now and it is not
+# really needed for testing that custom targets work. It is the responsibility
+# of the custom target to produce things in the correct format.
+assert(not meson.is_cross_build(),
+ 'MESON_SKIP_TEST cross checking not implemented.')
+
+cc = meson.get_compiler('c')
+genprog = find_program('generate_conflicting_stlibs.py')
+
+clib = custom_target('linkcustom',
+ output: ['libflob_1.a', 'libflob_2.a'],
+ command: [genprog,
+ '-o', '@OUTPUT@',
+ '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+
+clib_2 = clib[1]
+
+exe = executable('prog', 'prog.c', link_with: clib_2)
+test('linkcustom', exe)
+
+d = declare_dependency(link_with: clib_2)
+
+exe2 = executable('prog2', 'prog.c', dependencies: d)
+test('linkcustom2', exe2)
+
+# Link whole tests
+
+exe3 = executable('prog3', 'prog.c', link_whole: clib_2)
+test('linkwhole', exe)
+
+d2 = declare_dependency(link_whole: clib_2)
+
+exe4 = executable('prog4', 'prog.c', dependencies: d2)
+test('linkwhole2', exe2)
diff --git a/test cases/common/217 link custom_i single from multiple/prog.c b/test cases/common/217 link custom_i single from multiple/prog.c
new file mode 100644
index 0000000..8013034
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/prog.c
@@ -0,0 +1,5 @@
+int flob();
+
+int main(int argc, char **argv) {
+ return (flob() == 1 ? 0 : 1);
+}
diff --git a/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py b/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py
new file mode 100644
index 0000000..5292006
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+
+import shutil, sys, subprocess, argparse, pathlib
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--private-dir', required=True)
+parser.add_argument('-o', nargs='+', required=True)
+parser.add_argument('cmparr', nargs='+')
+
+contents = ['''#include<stdio.h>
+
+void flob_1() {
+ printf("Now flobbing #1.\\n");
+}
+''', '''#include<stdio.h>
+
+void flob_2() {
+ printf("Now flobbing #2.\\n");
+}
+''']
+
+def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
+ if shutil.which('ar'):
+ static_linker = 'ar'
+ elif shutil.which('llvm-ar'):
+ static_linker = 'llvm-ar'
+ elif shutil.which('gcc-ar'):
+ static_linker = 'gcc-ar'
+ else:
+ sys.exit('Could not detect a static linker.')
+ o_file = c_file.with_suffix('.o')
+ compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker, 'csr', outfile, str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+
+def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
+ static_linker = 'lib'
+ o_file = c_file.with_suffix('.obj')
+ compile_cmd = compiler_array + ['/MDd',
+ '/nologo',
+ '/ZI',
+ '/Ob0',
+ '/Od',
+ '/c',
+ '/Fo' + str(o_file),
+ str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker,
+ '/nologo',
+ '/OUT:' + str(outfile),
+ str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+def generate_lib(outfiles, private_dir, compiler_array):
+ private_dir = pathlib.Path(private_dir)
+ if not private_dir.exists():
+ private_dir.mkdir()
+
+ for i, content in enumerate(contents):
+ c_file = private_dir / ('flob_' + str(i + 1) + '.c')
+ c_file.write_text(content)
+ outfile = outfiles[i]
+
+ cl_found = False
+ for cl_arg in compiler_array:
+ if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
+ ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ else:
+ cl_found = True
+ break
+ if not cl_found:
+ ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ return 0
+
+if __name__ == '__main__':
+ options = parser.parse_args()
+ sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
diff --git a/test cases/common/218 link custom_i multiple from multiple/meson.build b/test cases/common/218 link custom_i multiple from multiple/meson.build
new file mode 100644
index 0000000..e5236e5
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/meson.build
@@ -0,0 +1,37 @@
+project('linkcustom', 'c')
+
+# This would require passing the static linker to the build script or having
+# it detect it by itself. I'm too lazy to implement it now and it is not
+# really needed for testing that custom targets work. It is the responsibility
+# of the custom target to produce things in the correct format.
+assert(not meson.is_cross_build(),
+ 'MESON_SKIP_TEST cross checking not implemented.')
+
+cc = meson.get_compiler('c')
+genprog = find_program('generate_stlibs.py')
+
+clib = custom_target('linkcustom',
+ output: ['libflob_1.a', 'libflob_2.a'],
+ command: [genprog,
+ '-o', '@OUTPUT@',
+ '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+
+clibs = [clib[0], clib[1]]
+
+exe = executable('prog', 'prog.c', link_with: clibs)
+test('linkcustom', exe)
+
+d = declare_dependency(link_with: clibs)
+
+exe2 = executable('prog2', 'prog.c', dependencies: d)
+test('linkcustom2', exe2)
+
+# Link whole tests
+
+exe3 = executable('prog3', 'prog.c', link_whole: clibs)
+test('linkwhole', exe)
+
+d2 = declare_dependency(link_whole: clibs)
+
+exe4 = executable('prog4', 'prog.c', dependencies: d2)
+test('linkwhole2', exe2)
diff --git a/test cases/common/218 link custom_i multiple from multiple/prog.c b/test cases/common/218 link custom_i multiple from multiple/prog.c
new file mode 100644
index 0000000..51effe6
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/prog.c
@@ -0,0 +1,8 @@
+void flob_1();
+void flob_2();
+
+int main(int argc, char **argv) {
+ flob_1();
+ flob_2();
+ return 0;
+}