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.
pull/6393/head
Daniel Mensinger 5 years ago committed by Jussi Pakkanen
parent d67423ab11
commit 4f6453bc32
  1. 66
      mesonbuild/cmake/interpreter.py
  2. 11
      mesonbuild/cmake/traceparser.py
  3. 9
      test cases/cmake/16 threads/main.cpp
  4. 8
      test cases/cmake/16 threads/meson.build
  5. 9
      test cases/cmake/16 threads/subprojects/cmMod/CMakeLists.txt
  6. 15
      test cases/cmake/16 threads/subprojects/cmMod/cmMod.cpp
  7. 10
      test cases/cmake/16 threads/subprojects/cmMod/cmMod.hpp
  8. 9
      test cases/cmake/16 threads/subprojects/cmMod/main.cpp
  9. 5
      test cases/cmake/2 advanced/meson.build
  10. 4
      test cases/cmake/2 advanced/subprojects/cmMod/CMakeLists.txt
  11. 5
      test cases/cmake/3 advanced no dep/meson.build
  12. 3
      test cases/cmake/3 advanced no dep/subprojects/cmMod/CMakeLists.txt

@ -301,6 +301,72 @@ class ConverterTarget:
self.public_compile_opts += props.get('INTERFACE_COMPILE_DEFINITIONS', []) self.public_compile_opts += props.get('INTERFACE_COMPILE_DEFINITIONS', [])
self.public_compile_opts += props.get('INTERFACE_COMPILE_OPTIONS', []) self.public_compile_opts += props.get('INTERFACE_COMPILE_OPTIONS', [])
self.link_flags += props.get('INTERFACE_LINK_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']: 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') mlog.warning('CMake: Target', mlog.bold(self.cmake_name), 'not found in CMake trace. This can lead to build errors')

@ -89,6 +89,7 @@ class CMakeTraceParser:
'target_compile_definitions': self._cmake_target_compile_definitions, 'target_compile_definitions': self._cmake_target_compile_definitions,
'target_compile_options': self._cmake_target_compile_options, 'target_compile_options': self._cmake_target_compile_options,
'target_include_directories': self._cmake_target_include_directories, 'target_include_directories': self._cmake_target_include_directories,
'target_link_libraries': self._cmake_target_link_libraries,
'target_link_options': self._cmake_target_link_options, 'target_link_options': self._cmake_target_link_options,
'add_dependencies': self._cmake_add_dependencies, 'add_dependencies': self._cmake_add_dependencies,
} }
@ -432,6 +433,10 @@ class CMakeTraceParser:
# DOC: https://cmake.org/cmake/help/latest/command/target_link_options.html # 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) 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): 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: if ignore is None:
ignore = ['BEFORE'] ignore = ['BEFORE']
@ -453,14 +458,14 @@ class CMakeTraceParser:
if i in ignore: if i in ignore:
continue continue
if i in ['INTERFACE', 'PUBLIC', 'PRIVATE']: if i in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'PRIVATE', 'LINK_PUBLIC', 'LINK_PRIVATE']:
mode = i mode = i
continue continue
if mode in ['INTERFACE', 'PUBLIC']: if mode in ['INTERFACE', 'LINK_INTERFACE_LIBRARIES', 'PUBLIC', 'LINK_PUBLIC']:
interface += [i] interface += [i]
if mode in ['PUBLIC', 'PRIVATE']: if mode in ['PUBLIC', 'PRIVATE', 'LINK_PRIVATE']:
private += [i] private += [i]
if paths: if paths:

@ -0,0 +1,9 @@
#include "cmMod.hpp"
#include <cstdlib>
int main() {
CmMod cc;
cc.asyncIncrement();
return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}

@ -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)

@ -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)

@ -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();
}

@ -0,0 +1,10 @@
#pragma once
class CmMod {
private:
int num = 0;
public:
inline int getNum() const { return num; }
void asyncIncrement();
};

@ -0,0 +1,9 @@
#include "cmMod.hpp"
#include <cstdlib>
int main() {
CmMod cc;
cc.asyncIncrement();
return cc.getNum() == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}

@ -10,11 +10,14 @@ cm = import('cmake')
# Test the "normal" subproject call # Test the "normal" subproject call
sub_pro = cm.subproject('cmMod') sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib') sub_dep = sub_pro.dependency('cmModLib')
sub_sta = sub_pro.dependency('cmModLibStatic')
# Build some files # Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep]) exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1) test('test1', exe1)
test('test2', exe2)
# Test if we can also extract executables # Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons') 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'))

@ -11,6 +11,7 @@ set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) 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) include(GenerateExportHeader)
generate_export_header(cmModLib) generate_export_header(cmModLib)
@ -19,6 +20,9 @@ set_target_properties(cmModLib PROPERTIES VERSION 1.0.1)
add_executable(testEXE main.cpp) 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_link_libraries(testEXE cmModLib)
target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)
install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin) install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)

@ -5,11 +5,14 @@ cm = import('cmake')
# Test the "normal" subproject call # Test the "normal" subproject call
sub_pro = cm.subproject('cmMod') sub_pro = cm.subproject('cmMod')
sub_dep = sub_pro.dependency('cmModLib') sub_dep = sub_pro.dependency('cmModLib')
sub_sta = sub_pro.dependency('cmModLibStatic')
# Build some files # Build some files
exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep]) exe1 = executable('main1', ['main.cpp'], dependencies: [sub_dep])
exe2 = executable('main2', ['main.cpp'], dependencies: [sub_sta])
test('test1', exe1) test('test1', exe1)
test('test2', exe2)
# Test if we can also extract executables # Test if we can also extract executables
assert(sub_pro.target_type('testEXE') == 'executable', 'The type must be executable for obvious reasons') 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'))

@ -9,6 +9,7 @@ set(CONFIG_OPT 42)
configure_file("config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) 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) include(GenerateExportHeader)
generate_export_header(cmModLib) generate_export_header(cmModLib)
@ -18,4 +19,6 @@ add_executable(testEXE main.cpp)
target_link_libraries(testEXE cmModLib) target_link_libraries(testEXE cmModLib)
target_compile_definitions(cmModLibStatic PUBLIC CMMODLIB_STATIC_DEFINE)
install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin) install(TARGETS cmModLib testEXE LIBRARY DESTINATION lib RUNTIME DESTINATION bin)

Loading…
Cancel
Save