per-target manual specification of link_language
This commit is contained in:
parent
16463046b1
commit
06bfc2dab6
|
@ -518,6 +518,8 @@ be passed to [shared and static libraries](#library).
|
||||||
depends on such as a symbol visibility map. The purpose is to
|
depends on such as a symbol visibility map. The purpose is to
|
||||||
automatically trigger a re-link (but not a re-compile) of the target
|
automatically trigger a re-link (but not a re-compile) of the target
|
||||||
when this file changes.
|
when this file changes.
|
||||||
|
- `link_language` since 0.51.0 makes the linker for this target
|
||||||
|
be for the specified language. This is helpful for multi-language targets.
|
||||||
- `link_whole` links all contents of the given static libraries
|
- `link_whole` links all contents of the given static libraries
|
||||||
whether they are used by not, equivalent to the
|
whether they are used by not, equivalent to the
|
||||||
`-Wl,--whole-archive` argument flag of GCC, available since 0.40.0.
|
`-Wl,--whole-archive` argument flag of GCC, available since 0.40.0.
|
||||||
|
@ -568,7 +570,7 @@ be passed to [shared and static libraries](#library).
|
||||||
the keyword argument for the default behaviour.
|
the keyword argument for the default behaviour.
|
||||||
- `override_options` takes an array of strings in the same format as
|
- `override_options` takes an array of strings in the same format as
|
||||||
`project`'s `default_options` overriding the values of these options
|
`project`'s `default_options` overriding the values of these options
|
||||||
for this target only, since 0.40.0
|
for this target only, since 0.40.0.
|
||||||
- `gnu_symbol_visibility` specifies how symbols should be exported, see
|
- `gnu_symbol_visibility` specifies how symbols should be exported, see
|
||||||
e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more
|
e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more
|
||||||
information. This value can either be an empty string or one of
|
information. This value can either be an empty string or one of
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
## New target keyword argument: `link_language`
|
||||||
|
There may be situations for which the user wishes to manually specify the linking language.
|
||||||
|
For example, a C++ target may link C, Fortran, etc. and perhaps the automatic detection in Meson does not pick the desired compiler.
|
||||||
|
The user can manually choose the linker by language per-target like this example of a target where one wishes to link with the Fortran compiler:
|
||||||
|
```meson
|
||||||
|
executable(..., link_language : 'fortran')
|
||||||
|
```
|
||||||
|
|
||||||
|
A specific case this option fixes is where for example the main program is Fortran that calls C and/or C++ code.
|
||||||
|
The automatic language detection of Meson prioritizes C/C++, and so an compile-time error results like `undefined reference to main`, because the linker is C or C++ instead of Fortran, which is fixed by this per-target override.
|
|
@ -12,6 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
from typing import List
|
||||||
import copy, os, re
|
import copy, os, re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import itertools, pathlib
|
import itertools, pathlib
|
||||||
|
@ -88,7 +89,7 @@ known_build_target_kwargs = (
|
||||||
rust_kwargs |
|
rust_kwargs |
|
||||||
cs_kwargs)
|
cs_kwargs)
|
||||||
|
|
||||||
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
|
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'link_language', 'pie'}
|
||||||
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'}
|
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'}
|
||||||
known_shmod_kwargs = known_build_target_kwargs
|
known_shmod_kwargs = known_build_target_kwargs
|
||||||
known_stlib_kwargs = known_build_target_kwargs | {'pic'}
|
known_stlib_kwargs = known_build_target_kwargs | {'pic'}
|
||||||
|
@ -425,7 +426,7 @@ a hard error in the future.''' % name)
|
||||||
|
|
||||||
self.option_overrides = self.parse_overrides(kwargs)
|
self.option_overrides = self.parse_overrides(kwargs)
|
||||||
|
|
||||||
def parse_overrides(self, kwargs):
|
def parse_overrides(self, kwargs) -> dict:
|
||||||
result = {}
|
result = {}
|
||||||
overrides = stringlistify(kwargs.get('override_options', []))
|
overrides = stringlistify(kwargs.get('override_options', []))
|
||||||
for o in overrides:
|
for o in overrides:
|
||||||
|
@ -437,7 +438,7 @@ a hard error in the future.''' % name)
|
||||||
result[k] = v
|
result[k] = v
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def is_linkable_target(self):
|
def is_linkable_target(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class BuildTarget(Target):
|
class BuildTarget(Target):
|
||||||
|
@ -454,6 +455,7 @@ class BuildTarget(Target):
|
||||||
self.objects = []
|
self.objects = []
|
||||||
self.external_deps = []
|
self.external_deps = []
|
||||||
self.include_dirs = []
|
self.include_dirs = []
|
||||||
|
self.link_language = kwargs.get('link_language')
|
||||||
self.link_targets = []
|
self.link_targets = []
|
||||||
self.link_whole_targets = []
|
self.link_whole_targets = []
|
||||||
self.link_depends = []
|
self.link_depends = []
|
||||||
|
@ -571,6 +573,9 @@ class BuildTarget(Target):
|
||||||
else:
|
else:
|
||||||
compilers = self.environment.coredata.compilers
|
compilers = self.environment.coredata.compilers
|
||||||
|
|
||||||
|
# did user override clink_langs for this target?
|
||||||
|
link_langs = [self.link_language] if self.link_language else clink_langs
|
||||||
|
|
||||||
# If this library is linked against another library we need to consider
|
# If this library is linked against another library we need to consider
|
||||||
# the languages of those libraries as well.
|
# the languages of those libraries as well.
|
||||||
if self.link_targets or self.link_whole_targets:
|
if self.link_targets or self.link_whole_targets:
|
||||||
|
@ -579,7 +584,7 @@ class BuildTarget(Target):
|
||||||
if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex):
|
if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex):
|
||||||
continue # We can't know anything about these.
|
continue # We can't know anything about these.
|
||||||
for name, compiler in t.compilers.items():
|
for name, compiler in t.compilers.items():
|
||||||
if name in clink_langs:
|
if name in link_langs:
|
||||||
extra.add((name, compiler))
|
extra.add((name, compiler))
|
||||||
for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
|
for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
|
||||||
self.compilers[name] = compiler
|
self.compilers[name] = compiler
|
||||||
|
@ -588,7 +593,7 @@ class BuildTarget(Target):
|
||||||
# No source files or parent targets, target consists of only object
|
# No source files or parent targets, target consists of only object
|
||||||
# files of unknown origin. Just add the first clink compiler
|
# files of unknown origin. Just add the first clink compiler
|
||||||
# that we have and hope that it can link these objects
|
# that we have and hope that it can link these objects
|
||||||
for lang in clink_langs:
|
for lang in link_langs:
|
||||||
if lang in compilers:
|
if lang in compilers:
|
||||||
self.compilers[lang] = compilers[lang]
|
self.compilers[lang] = compilers[lang]
|
||||||
break
|
break
|
||||||
|
@ -1149,7 +1154,7 @@ You probably should put it in link_with instead.''')
|
||||||
def get_aliases(self):
|
def get_aliases(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_langs_used_by_deps(self):
|
def get_langs_used_by_deps(self) -> List[str]:
|
||||||
'''
|
'''
|
||||||
Sometimes you want to link to a C++ library that exports C API, which
|
Sometimes you want to link to a C++ library that exports C API, which
|
||||||
means the linker must link in the C++ stdlib, and we must use a C++
|
means the linker must link in the C++ stdlib, and we must use a C++
|
||||||
|
@ -1159,6 +1164,11 @@ You probably should put it in link_with instead.''')
|
||||||
See: https://github.com/mesonbuild/meson/issues/1653
|
See: https://github.com/mesonbuild/meson/issues/1653
|
||||||
'''
|
'''
|
||||||
langs = []
|
langs = []
|
||||||
|
|
||||||
|
# User specified link_language of target (for multi-language targets)
|
||||||
|
if self.link_language:
|
||||||
|
return [self.link_language]
|
||||||
|
|
||||||
# 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:
|
if dep.language is None:
|
||||||
|
@ -1173,6 +1183,7 @@ You probably should put it in link_with instead.''')
|
||||||
for language in link_target.compilers:
|
for language in link_target.compilers:
|
||||||
if language not in langs:
|
if language not in langs:
|
||||||
langs.append(language)
|
langs.append(language)
|
||||||
|
|
||||||
return langs
|
return langs
|
||||||
|
|
||||||
def get_clink_dynamic_linker_and_stdlibs(self):
|
def get_clink_dynamic_linker_and_stdlibs(self):
|
||||||
|
|
|
@ -333,7 +333,6 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler):
|
||||||
def language_stdlib_only_link_flags(self):
|
def language_stdlib_only_link_flags(self):
|
||||||
return ['-lgfortran', '-lm']
|
return ['-lgfortran', '-lm']
|
||||||
|
|
||||||
|
|
||||||
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
|
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
|
||||||
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
|
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
|
||||||
GnuFortranCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs)
|
GnuFortranCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs)
|
||||||
|
@ -427,6 +426,9 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler):
|
||||||
FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags)
|
FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags)
|
||||||
PGICompiler.__init__(self, compiler_type)
|
PGICompiler.__init__(self, compiler_type)
|
||||||
|
|
||||||
|
def language_stdlib_only_link_flags(self) -> List[str]:
|
||||||
|
return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902',
|
||||||
|
'-lpgf90rtl', '-lpgftnrtl', '-lrt']
|
||||||
|
|
||||||
class FlangFortranCompiler(ClangCompiler, FortranCompiler):
|
class FlangFortranCompiler(ClangCompiler, FortranCompiler):
|
||||||
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
|
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
|
||||||
|
|
|
@ -505,6 +505,10 @@ def skippable(suite, test):
|
||||||
if test.endswith('netcdf'):
|
if test.endswith('netcdf'):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# MSVC doesn't link with GFortran
|
||||||
|
if test.endswith('14 fortran links c'):
|
||||||
|
return True
|
||||||
|
|
||||||
# No frameworks test should be skipped on linux CI, as we expect all
|
# No frameworks test should be skipped on linux CI, as we expect all
|
||||||
# prerequisites to be installed
|
# prerequisites to be installed
|
||||||
if mesonlib.is_linux():
|
if mesonlib.is_linux():
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void hello(void){
|
||||||
|
|
||||||
|
printf("hello from C\n");
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
interface
|
||||||
|
subroutine hello() bind (c)
|
||||||
|
end subroutine hello
|
||||||
|
end interface
|
||||||
|
|
||||||
|
call hello()
|
||||||
|
|
||||||
|
end program
|
|
@ -0,0 +1,13 @@
|
||||||
|
project('Fortran calling C', 'fortran', 'c')
|
||||||
|
|
||||||
|
ccid = meson.get_compiler('c').get_id()
|
||||||
|
if ccid == 'msvc' or ccid == 'clang-cl'
|
||||||
|
error('MESON_SKIP_TEST: MSVC and GCC do not interoperate like this.')
|
||||||
|
endif
|
||||||
|
|
||||||
|
c_lib = library('clib', 'clib.c')
|
||||||
|
|
||||||
|
f_call_c = executable('f_call_c', 'f_call_c.f90',
|
||||||
|
link_with: c_lib,
|
||||||
|
link_language: 'fortran')
|
||||||
|
test('Fortran calling C', f_call_c)
|
Loading…
Reference in New Issue