Can combine D and C++ in a single target. Closes #3125.

pull/3474/head
Jussi Pakkanen 7 years ago
parent 77b72e8573
commit 1918c0d231
  1. 13
      mesonbuild/backend/backends.py
  2. 8
      mesonbuild/backend/ninjabackend.py
  3. 16
      mesonbuild/build.py
  4. 6
      mesonbuild/compilers/compilers.py
  5. 6
      mesonbuild/compilers/cpp.py
  6. 6
      test cases/d/10 d cpp/cppmain.cpp
  7. 5
      test cases/d/10 d cpp/dmain.d
  8. 5
      test cases/d/10 d cpp/libfile.cpp
  9. 5
      test cases/d/10 d cpp/libfile.d
  10. 13
      test cases/d/10 d cpp/meson.build

@ -318,21 +318,18 @@ class Backend:
self.write_benchmark_file(datafile) self.write_benchmark_file(datafile)
return test_data, benchmark_data return test_data, benchmark_data
def determine_linker(self, target): def determine_linker_and_stdlib_args(self, target):
''' '''
If we're building a static library, there is only one static linker. If we're building a static library, there is only one static linker.
Otherwise, we query the target for the dynamic linker. Otherwise, we query the target for the dynamic linker.
''' '''
if isinstance(target, build.StaticLibrary): if isinstance(target, build.StaticLibrary):
if target.is_cross: if target.is_cross:
return self.build.static_cross_linker return self.build.static_cross_linker, []
else: else:
return self.build.static_linker return self.build.static_linker, []
l = target.get_clike_dynamic_linker() l, stdlib_args = target.get_clike_dynamic_linker_and_stdlibs()
if not l: return l, stdlib_args
m = "Couldn't determine linker for target {!r}"
raise MesonException(m.format(target.name))
return l
def rpaths_for_bundled_shared_libraries(self, target): def rpaths_for_bundled_shared_libraries(self, target):
paths = [] paths = []

@ -470,8 +470,8 @@ int dummy;
if is_unity: if is_unity:
for src in self.generate_unity_files(target, unity_src): for src in self.generate_unity_files(target, unity_src):
obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps)) obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps))
linker = self.determine_linker(target) linker, stdlib_args = self.determine_linker_and_stdlib_args(target)
elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects) elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args)
self.generate_shlib_aliases(target, self.get_target_dir(target)) self.generate_shlib_aliases(target, self.get_target_dir(target))
elem.write(outfile) elem.write(outfile)
@ -2485,7 +2485,7 @@ rule FORTRAN_DEP_HACK%s
return guessed_dependencies + absolute_libs return guessed_dependencies + absolute_libs
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]): def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[], stdlib_args=[]):
if isinstance(target, build.StaticLibrary): if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC' linker_base = 'STATIC'
else: else:
@ -2496,7 +2496,6 @@ rule FORTRAN_DEP_HACK%s
if target.is_cross: if target.is_cross:
crstr = '_CROSS' crstr = '_CROSS'
linker_rule = linker_base + crstr + '_LINKER' linker_rule = linker_base + crstr + '_LINKER'
# Create an empty commands list, and start adding link arguments from # Create an empty commands list, and start adding link arguments from
# various sources in the order in which they must override each other # various sources in the order in which they must override each other
# starting from hard-coded defaults followed by build options and so on. # starting from hard-coded defaults followed by build options and so on.
@ -2602,6 +2601,7 @@ rule FORTRAN_DEP_HACK%s
custom_target_libraries = self.get_custom_target_provided_libraries(target) custom_target_libraries = self.get_custom_target_provided_libraries(target)
commands += extra_args commands += extra_args
commands += custom_target_libraries commands += custom_target_libraries
commands += stdlib_args # Standard library arguments go last, because they never depend on anything.
# Convert from GCC-style link argument naming to the naming used by the # Convert from GCC-style link argument naming to the naming used by the
# current compiler. # current compiler.
commands = commands.to_native() commands = commands.to_native()

@ -989,6 +989,8 @@ You probably should put it in link_with instead.''')
langs = [] langs = []
# Check if any of the external libraries were written in this language # Check if any of the external libraries were written in this language
for dep in self.external_deps: for dep in self.external_deps:
if dep.language is None:
continue
if dep.language not in langs: if dep.language not in langs:
langs.append(dep.language) langs.append(dep.language)
# Check if any of the internal libraries this target links to were # Check if any of the internal libraries this target links to were
@ -999,7 +1001,7 @@ You probably should put it in link_with instead.''')
langs.append(language) langs.append(language)
return langs return langs
def get_clike_dynamic_linker(self): def get_clike_dynamic_linker_and_stdlibs(self):
''' '''
We use the order of languages in `clike_langs` to determine which We use the order of languages in `clike_langs` to determine which
linker to use in case the target has sources compiled with multiple linker to use in case the target has sources compiled with multiple
@ -1021,12 +1023,19 @@ You probably should put it in link_with instead.''')
for l in clike_langs: for l in clike_langs:
if l in self.compilers or l in dep_langs: if l in self.compilers or l in dep_langs:
try: try:
return all_compilers[l] linker = all_compilers[l]
except KeyError: except KeyError:
raise MesonException( raise MesonException(
'Could not get a dynamic linker for build target {!r}. ' 'Could not get a dynamic linker for build target {!r}. '
'Requires a linker for language "{}", but that is not ' 'Requires a linker for language "{}", but that is not '
'a project language.'.format(self.name, l)) 'a project language.'.format(self.name, l))
stdlib_args = []
added_languages = set()
for dl in itertools.chain(self.compilers, dep_langs):
if dl != linker.language:
stdlib_args += all_compilers[dl].language_stdlib_only_link_flags()
added_languages.add(dl)
return linker, stdlib_args
m = 'Could not get a dynamic linker for build target {!r}' m = 'Could not get a dynamic linker for build target {!r}'
raise AssertionError(m.format(self.name)) raise AssertionError(m.format(self.name))
@ -1049,7 +1058,8 @@ You probably should put it in link_with instead.''')
2. If the target contains only objects, process_compilers guesses and 2. If the target contains only objects, process_compilers guesses and
picks the first compiler that smells right. picks the first compiler that smells right.
''' '''
linker = self.get_clike_dynamic_linker() linker, _ = self.get_clike_dynamic_linker_and_stdlibs()
# Mixing many languages with MSVC is not supported yet so ignore stdlibs.
if linker and linker.get_id() == 'msvc': if linker and linker.get_id() == 'msvc':
return True return True
return False return False

@ -938,6 +938,12 @@ class Compiler:
def openmp_flags(self): def openmp_flags(self):
raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language()) raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
def language_stdlib_only_link_flags(self):
# The linker flags needed to link the standard library of the current
# language in. This is needed in cases where you e.g. combine D and C++
# and both of which need to link their runtime library in or otherwise
# building fails with undefined symbols.
return []
GCC_STANDARD = 0 GCC_STANDARD = 0
GCC_OSX = 1 GCC_OSX = 1

@ -93,6 +93,9 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def get_option_link_args(self, options): def get_option_link_args(self, options):
return [] return []
def language_stdlib_only_link_flags(self):
return ['-lstdc++']
class GnuCPPCompiler(GnuCompiler, CPPCompiler): class GnuCPPCompiler(GnuCompiler, CPPCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines, **kwargs): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines, **kwargs):
@ -134,6 +137,9 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
def get_pch_use_args(self, pch_dir, header): def get_pch_use_args(self, pch_dir, header):
return ['-fpch-preprocess', '-include', os.path.basename(header)] return ['-fpch-preprocess', '-include', os.path.basename(header)]
def language_stdlib_only_link_flags(self):
return ['-lstdc++']
class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):

@ -0,0 +1,6 @@
extern void print_hello(int i);
int main(int, char**) {
print_hello(1);
return 0;
}

@ -0,0 +1,5 @@
extern (C++) void print_hello(int i);
void main() {
print_hello(1);
}

@ -0,0 +1,5 @@
#include<iostream>
void print_hello(int i) {
std::cout << "Hello. Here is a number printed with C++: " << i << ".\n";
}

@ -0,0 +1,5 @@
import std.stdio;
extern (C++) void print_hello(int i) {
writefln("Hello. Here is a number printed with D: %d", i);
}

@ -0,0 +1,13 @@
project('d and c++', 'd', 'cpp')
cpp = meson.get_compiler('cpp')
if cpp.get_id() == 'clang'
error('MESON_SKIP_TEST combining Clang C++ with GDC produces broken executables.')
endif
e1 = executable('dcpp', 'dmain.d', 'libfile.cpp')
test('dcpp', e1)
e2 = executable('cppd', 'cppmain.cpp', 'libfile.d')
test('cppd', e2)
Loading…
Cancel
Save