Merge pull request #1654 from dcbaker/c-cpp-link

Add a testcase for linking C and C++ static archives into a shared li…
pull/1660/head
Jussi Pakkanen 8 years ago committed by GitHub
commit 33b5ddf35e
  1. 37
      mesonbuild/build.py
  2. 18
      mesonbuild/dependencies.py
  3. 13
      mesonbuild/interpreter.py
  4. 19
      test cases/common/146 C and CPP link/foo.c
  5. 31
      test cases/common/146 C and CPP link/foo.cpp
  6. 16
      test cases/common/146 C and CPP link/foo.h
  7. 24
      test cases/common/146 C and CPP link/foo.hpp
  8. 23
      test cases/common/146 C and CPP link/foobar.c
  9. 16
      test cases/common/146 C and CPP link/foobar.h
  10. 58
      test cases/common/146 C and CPP link/meson.build

@ -868,6 +868,28 @@ You probably should put it in link_with instead.''')
def get_aliases(self):
return {}
def get_langs_used_by_deps(self):
'''
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++
compiler for linking. The same is also applicable for objc/objc++, etc,
so we can keep using clike_langs for the priority order.
See: https://github.com/mesonbuild/meson/issues/1653
'''
langs = []
# Check if any of the external libraries were written in this language
for dep in self.external_deps:
if dep.language not in langs:
langs.append(dep.language)
# Check if any of the internal libraries this target links to were
# written in this language
for link_target in self.link_targets:
for language in link_target.compilers:
if language not in langs:
langs.append(language)
return langs
def get_clike_dynamic_linker(self):
'''
We use the order of languages in `clike_langs` to determine which
@ -878,9 +900,20 @@ You probably should put it in link_with instead.''')
that can link compiled C. We don't actually need to add an exception
for Vala here because of that.
'''
# Populate list of all compilers, not just those being used to compile
# sources in this target
if self.is_cross:
all_compilers = self.environment.coredata.cross_compilers
else:
all_compilers = self.environment.coredata.compilers
# Languages used by dependencies
dep_langs = self.get_langs_used_by_deps()
# Pick a compiler based on the language priority-order
for l in clike_langs:
if l in self.compilers:
return self.compilers[l]
if l in self.compilers or l in dep_langs:
return all_compilers[l]
m = 'Could not get a dynamic linker for build target {!r}'
raise AssertionError(m.format(self.name))
def get_using_msvc(self):
'''

@ -51,6 +51,7 @@ class DependencyMethods(Enum):
class Dependency:
def __init__(self, type_name, kwargs):
self.name = "null"
self.language = None
self.is_found = False
self.type_name = type_name
method = DependencyMethods(kwargs.get('method', 'auto'))
@ -570,11 +571,12 @@ class ExternalProgram:
return self.name
class ExternalLibrary(Dependency):
# TODO: Add `lang` to the parent Dependency object so that dependencies can
# be expressed for languages other than C-like
def __init__(self, name, link_args=None, language=None, silent=False):
# TODO: Add `language` support to all Dependency objects so that languages
# can be exposed for dependencies that support that (i.e., not pkg-config)
def __init__(self, name, link_args, language, silent=False):
super().__init__('external', {})
self.name = name
self.language = language
self.is_found = False
self.link_args = []
self.lang_args = []
@ -582,9 +584,13 @@ class ExternalLibrary(Dependency):
self.is_found = True
if not isinstance(link_args, list):
link_args = [link_args]
if language:
self.lang_args = {language: link_args}
else:
self.lang_args = {language: link_args}
# We special-case Vala for now till the Dependency object gets
# proper support for exposing the language it was written in.
# Without this, vala-specific link args will end up in the C link
# args list if you link to a Vala library.
# This hack use to be in CompilerHolder.find_library().
if language != 'vala':
self.link_args = link_args
if not silent:
if self.is_found:

@ -982,14 +982,7 @@ class CompilerHolder(InterpreterObject):
if required and not linkargs:
l = self.compiler.language.capitalize()
raise InterpreterException('{} library {!r} not found'.format(l, libname))
# If this is set to None, the library and link arguments are for
# a C-like compiler. Otherwise, it's for some other language that has
# a find_library implementation. We do this because it's easier than
# maintaining a list of languages that can consume C libraries.
lang = None
if self.compiler.language == 'vala':
lang = 'vala'
lib = dependencies.ExternalLibrary(libname, linkargs, language=lang)
lib = dependencies.ExternalLibrary(libname, linkargs, self.compiler.language)
return ExternalLibraryHolder(lib)
def has_argument_method(self, args, kwargs):
@ -2320,9 +2313,11 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Input must be a string or a file')
if isinstance(inputfile, str):
inputfile = os.path.join(self.subdir, inputfile)
ifile_abs = os.path.join(self.environment.source_dir, inputfile)
else:
ifile_abs = inputfile.absolute_path(self.environment.source_dir,
self.environment.build_dir)
inputfile = inputfile.relative_name()
ifile_abs = os.path.join(self.environment.source_dir, inputfile)
elif 'command' in kwargs and '@INPUT@' in kwargs['command']:
raise InterpreterException('@INPUT@ used as command argument, but no input file specified.')
# Validate output

@ -0,0 +1,19 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "foo.h"
int forty_two(void) {
return 42;
}

@ -0,0 +1,31 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
const int cnums[] = {0, 61};
template<typename T, int N>
std::vector<T> makeVector(const T (&data)[N])
{
return std::vector<T>(data, data+N);
}
namespace {
std::vector<int> numbers = makeVector(cnums);
}
extern "C" int six_one(void) {
return numbers[1];
}

@ -0,0 +1,16 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
int forty_two(void);

@ -0,0 +1,24 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __cplusplus
extern "C" {
#endif
int six_one(void);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,23 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "foo.h"
#include "foo.hpp"
#include "foobar.h"
void mynumbers(int nums[]) {
nums[0] = forty_two();
nums[1] = six_one();
}

@ -0,0 +1,16 @@
/* Copyright © 2017 Dylan Baker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
void mynumbers(int nums[]);

@ -0,0 +1,58 @@
# Copyright © 2017 Dylan Baker
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
project('C and C++ static link test', ['c', 'cpp'])
libc = static_library('cfoo', ['foo.c', 'foo.h'])
# Test that linking C libs to external static C++ libs uses the C++ linker
# Since we can't depend on the test system to provide this, we create one
# ourselves at configure time and then 'find' it with cxx.find_library().
cxx = meson.get_compiler('cpp')
if cxx.get_id() == 'msvc'
compile_cmd = ['/c', '@INPUT@', '/Fo@OUTPUT@']
stlib_cmd = ['lib', '/OUT:@OUTPUT@', '@INPUT@']
else
compile_cmd = ['-c', '-fPIC', '@INPUT@', '-o', '@OUTPUT@']
stlib_cmd = ['ar', 'csr', '@OUTPUT@', '@INPUT@']
endif
foo_cpp_o = configure_file(
input : 'foo.cpp',
output : 'foo.cpp.o',
command : cxx.cmd_array() + compile_cmd)
configure_file(
input : foo_cpp_o,
output : 'libstcppext.a',
command : stlib_cmd)
libstcppext = cxx.find_library('stcppext', dirs : meson.current_build_dir())
libfooext = shared_library(
'fooext',
['foobar.c', 'foobar.h'],
link_with : libc,
dependencies : libstcppext,
)
# Test that linking C libs to internal static C++ libs uses the C++ linker
libcpp = static_library('cppfoo', ['foo.cpp', 'foo.hpp'])
libfoo = shared_library(
'foo',
['foobar.c', 'foobar.h'],
link_with : [libc, libcpp],
)
Loading…
Cancel
Save