aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hirsch, Ph.D <10931741+scivision@users.noreply.github.com>2019-05-02 16:26:51 -0400
committerJussi Pakkanen <jpakkane@gmail.com>2019-05-02 23:26:51 +0300
commit06bfc2dab61c5bf79265a8db777b02732ee86ecf (patch)
tree0ed6065a804d972c950826b86e1241ed86b759ce
parent16463046b10818910da72d892d53663496179606 (diff)
downloadmeson-06bfc2dab61c5bf79265a8db777b02732ee86ecf.zip
meson-06bfc2dab61c5bf79265a8db777b02732ee86ecf.tar.gz
meson-06bfc2dab61c5bf79265a8db777b02732ee86ecf.tar.bz2
per-target manual specification of link_language
-rw-r--r--docs/markdown/Reference-manual.md4
-rw-r--r--docs/markdown/snippets/link_language.md10
-rw-r--r--mesonbuild/build.py23
-rw-r--r--mesonbuild/compilers/fortran.py4
-rwxr-xr-xrun_project_tests.py4
-rw-r--r--test cases/fortran/14 fortran links c/clib.c7
-rw-r--r--test cases/fortran/14 fortran links c/f_call_c.f9010
-rw-r--r--test cases/fortran/14 fortran links c/meson.build13
8 files changed, 67 insertions, 8 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 056612d..d86d825 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -518,6 +518,8 @@ be passed to [shared and static libraries](#library).
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
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
whether they are used by not, equivalent to the
`-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.
- `override_options` takes an array of strings in the same format as
`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
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
diff --git a/docs/markdown/snippets/link_language.md b/docs/markdown/snippets/link_language.md
new file mode 100644
index 0000000..28ebe8b
--- /dev/null
+++ b/docs/markdown/snippets/link_language.md
@@ -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.
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 1fad9e0..603e0d0 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from typing import List
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
@@ -88,7 +89,7 @@ known_build_target_kwargs = (
rust_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_shmod_kwargs = known_build_target_kwargs
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)
- def parse_overrides(self, kwargs):
+ def parse_overrides(self, kwargs) -> dict:
result = {}
overrides = stringlistify(kwargs.get('override_options', []))
for o in overrides:
@@ -437,7 +438,7 @@ a hard error in the future.''' % name)
result[k] = v
return result
- def is_linkable_target(self):
+ def is_linkable_target(self) -> bool:
return False
class BuildTarget(Target):
@@ -454,6 +455,7 @@ class BuildTarget(Target):
self.objects = []
self.external_deps = []
self.include_dirs = []
+ self.link_language = kwargs.get('link_language')
self.link_targets = []
self.link_whole_targets = []
self.link_depends = []
@@ -571,6 +573,9 @@ class BuildTarget(Target):
else:
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
# the languages of those libraries as well.
if self.link_targets or self.link_whole_targets:
@@ -579,7 +584,7 @@ class BuildTarget(Target):
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:
+ if name in link_langs:
extra.add((name, compiler))
for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
self.compilers[name] = compiler
@@ -588,7 +593,7 @@ class BuildTarget(Target):
# No source files or parent targets, target consists of only object
# files of unknown origin. Just add the first clink compiler
# 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:
self.compilers[lang] = compilers[lang]
break
@@ -1149,7 +1154,7 @@ You probably should put it in link_with instead.''')
def get_aliases(self):
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
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
'''
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
for dep in self.external_deps:
if dep.language is None:
@@ -1173,6 +1183,7 @@ You probably should put it in link_with instead.''')
for language in link_target.compilers:
if language not in langs:
langs.append(language)
+
return langs
def get_clink_dynamic_linker_and_stdlibs(self):
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index dd54fd0..86ebe05 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -333,7 +333,6 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler):
def language_stdlib_only_link_flags(self):
return ['-lgfortran', '-lm']
-
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
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)
@@ -427,6 +426,9 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler):
FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags)
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):
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
diff --git a/run_project_tests.py b/run_project_tests.py
index c1d42fc..29716aa 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -505,6 +505,10 @@ def skippable(suite, test):
if test.endswith('netcdf'):
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
# prerequisites to be installed
if mesonlib.is_linux():
diff --git a/test cases/fortran/14 fortran links c/clib.c b/test cases/fortran/14 fortran links c/clib.c
new file mode 100644
index 0000000..81b2e0c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/clib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void hello(void){
+
+ printf("hello from C\n");
+
+}
diff --git a/test cases/fortran/14 fortran links c/f_call_c.f90 b/test cases/fortran/14 fortran links c/f_call_c.f90
new file mode 100644
index 0000000..af1e79c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/f_call_c.f90
@@ -0,0 +1,10 @@
+implicit none
+
+interface
+subroutine hello() bind (c)
+end subroutine hello
+end interface
+
+call hello()
+
+end program
diff --git a/test cases/fortran/14 fortran links c/meson.build b/test cases/fortran/14 fortran links c/meson.build
new file mode 100644
index 0000000..163aec6
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/meson.build
@@ -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)