aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2019-12-28 13:37:31 +0100
committerJussi Pakkanen <jpakkane@gmail.com>2019-12-29 19:02:24 +0200
commit4f6453bc327d91c29956459951a06bcdc73ba040 (patch)
tree2eecc6438dfa3399c67b67a0ea58ef8a49720481
parentd67423ab11bbcd0e81d81005608a97363804f6a2 (diff)
downloadmeson-4f6453bc327d91c29956459951a06bcdc73ba040.zip
meson-4f6453bc327d91c29956459951a06bcdc73ba040.tar.gz
meson-4f6453bc327d91c29956459951a06bcdc73ba040.tar.bz2
cmake: Use trace for missing link flags (fixes #6386)
This is neccessary for static libraries, since the CMake file API does not add link flags here.
-rw-r--r--mesonbuild/cmake/interpreter.py66
-rw-r--r--mesonbuild/cmake/traceparser.py11
-rw-r--r--test cases/cmake/16 threads/main.cpp9
-rw-r--r--test cases/cmake/16 threads/meson.build8
-rw-r--r--test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt9
-rw-r--r--test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp15
-rw-r--r--test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp10
-rw-r--r--test cases/cmake/16 threads/subprojects/cmMod/main.cpp9
-rw-r--r--test cases/cmake/2 advanced/meson.build5
-rw-r--r--test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt8
-rw-r--r--test cases/cmake/3 advanced no dep/meson.build5
-rw-r--r--test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt5
12 files changed, 152 insertions, 8 deletions
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 66d0994..5f887ee 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -301,6 +301,72 @@ class ConverterTarget:
self.public_compile_opts += props.get('INTERFACE_COMPILE_DEFINITIONS', [])
self.public_compile_opts += props.get('INTERFACE_COMPILE_OPTIONS', [])
self.link_flags += props.get('INTERFACE_LINK_OPTIONS', [])
+
+ # TODO refactor this copy paste from CMakeDependency for future releases
+ reg_is_lib = re.compile(r'^(-l[a-zA-Z0-9_]+|-l?pthread)$')
+ to_process = [self.cmake_name]
+ processed = []
+ while len(to_process) > 0:
+ curr = to_process.pop(0)
+
+ if curr in processed or curr not in trace.targets:
+ continue
+
+ tgt = trace.targets[curr]
+ cfgs = []
+ cfg = ''
+ otherDeps = []
+ libraries = []
+ mlog.debug(tgt)
+
+ if 'INTERFACE_COMPILE_DEFINITIONS' in tgt.properties:
+ self.public_compile_opts += ['-D' + re.sub('^-D', '', x) for x in tgt.properties['INTERFACE_COMPILE_DEFINITIONS'] if x]
+
+ if 'INTERFACE_COMPILE_OPTIONS' in tgt.properties:
+ self.public_compile_opts += [x for x in tgt.properties['INTERFACE_COMPILE_OPTIONS'] if x]
+
+ if 'IMPORTED_CONFIGURATIONS' in tgt.properties:
+ cfgs += [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
+ cfg = cfgs[0]
+
+ if 'CONFIGURATIONS' in tgt.properties:
+ cfgs += [x for x in tgt.properties['CONFIGURATIONS'] if x]
+ cfg = cfgs[0]
+
+ if 'RELEASE' in cfgs:
+ cfg = 'RELEASE'
+
+ if 'IMPORTED_IMPLIB_{}'.format(cfg) in tgt.properties:
+ libraries += [x for x in tgt.properties['IMPORTED_IMPLIB_{}'.format(cfg)] if x]
+ elif 'IMPORTED_IMPLIB' in tgt.properties:
+ libraries += [x for x in tgt.properties['IMPORTED_IMPLIB'] if x]
+ elif 'IMPORTED_LOCATION_{}'.format(cfg) in tgt.properties:
+ libraries += [x for x in tgt.properties['IMPORTED_LOCATION_{}'.format(cfg)] if x]
+ elif 'IMPORTED_LOCATION' in tgt.properties:
+ libraries += [x for x in tgt.properties['IMPORTED_LOCATION'] if x]
+
+ if 'LINK_LIBRARIES' in tgt.properties:
+ otherDeps += [x for x in tgt.properties['LINK_LIBRARIES'] if x]
+
+ if 'INTERFACE_LINK_LIBRARIES' in tgt.properties:
+ otherDeps += [x for x in tgt.properties['INTERFACE_LINK_LIBRARIES'] if x]
+
+ if 'IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg) in tgt.properties:
+ otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES_{}'.format(cfg)] if x]
+ elif 'IMPORTED_LINK_DEPENDENT_LIBRARIES' in tgt.properties:
+ otherDeps += [x for x in tgt.properties['IMPORTED_LINK_DEPENDENT_LIBRARIES'] if x]
+
+ for j in otherDeps:
+ if j in trace.targets:
+ to_process += [j]
+ elif reg_is_lib.match(j) or os.path.exists(j):
+ libraries += [j]
+
+ for j in libraries:
+ if j not in self.link_libraries:
+ self.link_libraries += [j]
+
+ processed += [curr]
elif self.type.upper() not in ['EXECUTABLE', 'OBJECT_LIBRARY']:
mlog.warning('CMake: Target', mlog.bold(self.cmake_name), 'not found in CMake trace. This can lead to build errors')
diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py
index 50cabab..84b2120 100644
--- a/mesonbuild/cmake/traceparser.py
+++ b/mesonbuild/cmake/traceparser.py
@@ -89,6 +89,7 @@ class CMakeTraceParser:
'target_compile_definitions': self._cmake_target_compile_definitions,
'target_compile_options': self._cmake_target_compile_options,
'target_include_directories': self._cmake_target_include_directories,
+ 'target_link_libraries': self._cmake_target_link_libraries,
'target_link_options': self._cmake_target_link_options,
'add_dependencies': self._cmake_add_dependencies,
}
@@ -432,6 +433,10 @@ class CMakeTraceParser:
# DOC: https://cmake.org/cmake/help/latest/command/target_link_options.html
self._parse_common_target_options('target_link_options', 'LINK_OPTIONS', 'INTERFACE_LINK_OPTIONS', tline)
+ def _cmake_target_link_libraries(self, tline: CMakeTraceLine) -> None:
+ # DOC: https://cmake.org/cmake/help/latest/command/target_link_libraries.html
+ self._parse_common_target_options('target_link_options', 'LINK_LIBRARIES', 'INTERFACE_LINK_LIBRARIES', tline)
+
def _parse_common_target_options(self, func: str, private_prop: str, interface_prop: str, tline: CMakeTraceLine, ignore: Optional[List[str]] = None, paths: bool = False):
if ignore is None:
ignore = ['BEFORE']
@@ -453,14 +458,14 @@ class CMakeTraceParser:
if i in ignore:
continue
- if i in ['INTERFACE', 'PUBLIC', 'PRIVATE']:
+ if i in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'PRIVATE', 'LINK_PUBLIC', 'LINK_PRIVATE']:
mode = i
continue
- if mode in ['INTERFACE', 'PUBLIC']:
+ if mode in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'LINK_PUBLIC']:
interface += [i]
- if mode in ['PUBLIC', 'PRIVATE']:
+ if mode in ['PUBLIC', 'PRIVATE', 'LINK_PRIVATE']:
private += [i]
if paths:
diff --git a/test cases/cmake/16 threads/main.cpp b/test cases/cmake/16 threads/main.cpp
new file mode 100644
index 0000000..67ee110
--- /dev/null
+++ b/test cases/cmake/16 threads/main.cpp
@@ -0,0 +1,9 @@
+#include "cmMod.hpp"
+
+#include <cstdlib>
+
+int main() {
+ CmMod cc;
+ cc.asyncIncrement();
+ return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test cases/cmake/16 threads/meson.build b/test cases/cmake/16 threads/meson.build
new file mode 100644
index 0000000..d7ade1c
--- /dev/null
+++ b/test cases/cmake/16 threads/meson.build
@@ -0,0 +1,8 @@
+project('cmMod', ['c', 'cpp'])
+
+cm = import('cmake')
+cmMod = cm.subproject('cmMod')
+cmModDep = cmMod.dependency('cmModLib')
+
+exe1 = executable('exe1', ['main.cpp'], dependencies: [cmModDep])
+test('exe1_OK', exe1)
diff --git a/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt
new file mode 100644
index 0000000..37d32c1
--- /dev/null
+++ b/test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(cmMod CXX)
+set (CMAKE_CXX_STANDARD 14)
+
+find_package(Threads)
+
+add_library(cmModLib STATIC cmMod.cpp)
+target_link_libraries(cmModLib PRIVATE Threads::Threads)
diff --git a/test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp b/test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp
new file mode 100644
index 0000000..f971eeb
--- /dev/null
+++ b/test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp
@@ -0,0 +1,15 @@
+#include "cmMod.hpp"
+
+#include <chrono>
+#include <thread>
+
+using namespace std::chrono_literals;
+
+void CmMod::asyncIncrement() {
+ std::thread t1([this]() {
+ std::this_thread::sleep_for(100ms);
+ num += 1;
+ });
+
+ t1.join();
+}
diff --git a/test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp b/test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp
new file mode 100644
index 0000000..1c85a8b
--- /dev/null
+++ b/test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+class CmMod {
+private:
+ int num = 0;
+
+public:
+ inline int getNum() const { return num; }
+ void asyncIncrement();
+};
diff --git a/test cases/cmake/16 threads/subprojects/cmMod/main.cpp b/test cases/cmake/16 threads/subprojects/cmMod/main.cpp
new file mode 100644
index 0000000..67ee110
--- /dev/null
+++ b/test cases/cmake/16 threads/subprojects/cmMod/main.cpp
@@ -0,0 +1,9 @@
+#include "cmMod.hpp"
+
+#include <cstdlib>
+
+int main() {
+ CmMod cc;
+ cc.asyncIncrement();
+ return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test cases/cmake/2 advanced/meson.build b/test cases/cmake/2 advanced/meson.build
index 385a49b..a10db1c 100644
--- a/test cases/cmake/2 advanced/meson.build
+++ b/test cases/cmake/2 advanced/meson.build
@@ -10,11 +10,14 @@ cm = import('cmake')
# Test the "normal" subproject call
sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')
+sub_sta = sub_pro.dependency('cmModLibStatic')
# Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
+exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1)
+test('test2', exe2)
# Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons')
-test('test2', sub_pro.target('testEXE'))
+test('test3', sub_pro.target('testEXE'))
diff --git a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt
index 05ccb9e..50b1049 100644
--- a/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt
+++ b/test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt
@@ -10,7 +10,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CM
set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
-add_library(cmModLib SHARED lib/cmMod.cpp)
+add_library(cmModLib SHARED lib/cmMod.cpp)
+add_library(cmModLibStatic STATIC lib/cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)
@@ -18,7 +19,10 @@ set_target_properties(cmModLib PROPERTIES VERSION 1.0.1)
add_executable(testEXE main.cpp)
-target_link_libraries(cmModLib ZLIB::ZLIB)
+target_link_libraries(cmModLib ZLIB::ZLIB)
+target_link_libraries(cmModLibStatic ZLIB::ZLIB)
target_link_libraries(testEXE cmModLib)
+target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)
+
install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)
diff --git a/test cases/cmake/3 advanced no dep/meson.build b/test cases/cmake/3 advanced no dep/meson.build
index c10dbf5..0d1e127 100644
--- a/test cases/cmake/3 advanced no dep/meson.build
+++ b/test cases/cmake/3 advanced no dep/meson.build
@@ -5,11 +5,14 @@ cm = import('cmake')
# Test the "normal" subproject call
sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib')
+sub_sta = sub_pro.dependency('cmModLibStatic')
# Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
+exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1)
+test('test2', exe2)
# Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons')
-test('test2', sub_pro.target('testEXE'))
+test('test3', sub_pro.target('testEXE'))
diff --git a/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt b/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt
index 2f6267d..38c1fff 100644
--- a/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt
+++ b/test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt
@@ -8,7 +8,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CM
set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
-add_library(cmModLib SHARED lib/cmMod.cpp)
+add_library(cmModLib SHARED lib/cmMod.cpp)
+add_library(cmModLibStatic STATIC lib/cmMod.cpp)
include(GenerateExportHeader)
generate_export_header(cmModLib)
@@ -18,4 +19,6 @@ add_executable(testEXE main.cpp)
target_link_libraries(testEXE cmModLib)
+target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)
+
install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)