Merge pull request #3474 from mesonbuild/dcpp
Can combine D and C++ in a single target.
This commit is contained in:
commit
6c115f1626
|
@ -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):
|
||||||
|
|
|
@ -183,13 +183,15 @@ class GnuFortranCompiler(FortranCompiler):
|
||||||
def openmp_flags(self):
|
def openmp_flags(self):
|
||||||
return ['-fopenmp']
|
return ['-fopenmp']
|
||||||
|
|
||||||
|
def language_stdlib_only_link_flags(self):
|
||||||
|
return ['-lgfortran', '-lm', '-lquadmath']
|
||||||
|
|
||||||
|
|
||||||
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
|
class ElbrusFortranCompiler(GnuFortranCompiler, 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):
|
||||||
GnuFortranCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
|
GnuFortranCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
|
||||||
ElbrusCompiler.__init__(self, gcc_type, defines)
|
ElbrusCompiler.__init__(self, gcc_type, defines)
|
||||||
|
|
||||||
|
|
||||||
class G95FortranCompiler(FortranCompiler):
|
class G95FortranCompiler(FortranCompiler):
|
||||||
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
|
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
|
||||||
super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags)
|
super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags)
|
||||||
|
|
|
@ -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)
|
|
@ -0,0 +1,5 @@
|
||||||
|
function fortran() bind(C)
|
||||||
|
use, intrinsic :: iso_c_binding
|
||||||
|
real(kind=c_double) :: fortran
|
||||||
|
fortran = 2.0**rand(1)
|
||||||
|
end function fortran
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" double fortran();
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
std::cout << "FORTRAN gave us this number: " << fortran() << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
project('C++ and FORTRAN', 'cpp', 'fortran')
|
||||||
|
|
||||||
|
cpp = meson.get_compiler('cpp')
|
||||||
|
|
||||||
|
if cpp.get_id() == 'clang'
|
||||||
|
error('MESON_SKIP_TEST Clang C++ does not find -lgfortran for some reason.')
|
||||||
|
endif
|
||||||
|
|
||||||
|
e = executable('cppfort', 'main.cpp', 'fortran.f')
|
||||||
|
test('C++ FORTRAN', e)
|
Loading…
Reference in New Issue