From 1041c71eb0370041492055fff5c7a2bffd306b58 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sat, 23 Feb 2019 15:02:33 +0100 Subject: [PATCH] cmake: support object libraries --- mesonbuild/cmake/interpreter.py | 43 +++++++++++++++++-- mesonbuild/interpreter.py | 11 +++-- test cases/cmake/4 object library/main.cpp | 9 ++++ test cases/cmake/4 object library/meson.build | 14 ++++++ .../subprojects/cmObjLib/CMakeLists.txt | 10 +++++ .../subprojects/cmObjLib/libA.cpp | 5 +++ .../subprojects/cmObjLib/libA.hpp | 5 +++ .../subprojects/cmObjLib/libB.cpp | 6 +++ .../subprojects/cmObjLib/libB.hpp | 5 +++ 9 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 test cases/cmake/4 object library/main.cpp create mode 100644 test cases/cmake/4 object library/meson.build create mode 100644 test cases/cmake/4 object library/subprojects/cmObjLib/CMakeLists.txt create mode 100644 test cases/cmake/4 object library/subprojects/cmObjLib/libA.cpp create mode 100644 test cases/cmake/4 object library/subprojects/cmObjLib/libA.hpp create mode 100644 test cases/cmake/4 object library/subprojects/cmObjLib/libB.cpp create mode 100644 test cases/cmake/4 object library/subprojects/cmObjLib/libB.hpp diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index ae42ae7e8..7073e943f 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -20,11 +20,11 @@ from .client import CMakeClient, RequestCMakeInputs, RequestConfigure, RequestCo from .. import mlog from ..build import Build from ..environment import Environment -from ..mparser import Token, BaseNode, CodeBlockNode, FunctionNode, ArrayNode, ArgumentNode, AssignmentNode, BooleanNode, StringNode, IdNode +from ..mparser import Token, BaseNode, CodeBlockNode, FunctionNode, ArrayNode, ArgumentNode, AssignmentNode, BooleanNode, StringNode, IdNode, MethodNode from ..backend.backends import Backend from ..dependencies.base import CMakeDependency, ExternalProgram from subprocess import Popen, PIPE, STDOUT -from typing import Dict +from typing import Dict, List import os, re CMAKE_BACKEND_GENERATOR_MAP = { @@ -50,6 +50,7 @@ CMAKE_TGT_TYPE_MAP = { 'MODULE_LIBRARY': 'shared_module', 'SHARED_LIBRARY': 'shared_library', 'EXECUTABLE': 'executable', + 'OBJECT_LIBRARY': 'static_library', } class ConverterTarget: @@ -75,6 +76,7 @@ class ConverterTarget: self.generated = [] self.includes = [] self.link_with = [] + self.object_libs = [] self.compile_opts = {} self.pie = False @@ -160,6 +162,17 @@ class ConverterTarget: if os.path.commonpath([self.install_dir, install_prefix]) == install_prefix: self.install_dir = os.path.relpath(self.install_dir, install_prefix) + def process_object_libs(self, obj_target_list: List['ConverterTarget']): + # Try to detect the object library(s) from the generated input sources + temp = [os.path.basename(x) for x in self.generated if x.endswith('.o')] + self.generated = [x for x in self.generated if not x.endswith('.o')] + for i in obj_target_list: + out_objects = [os.path.basename(x + '.o') for x in i.sources + i.generated] + for j in out_objects: + if j in temp: + self.object_libs += [i] + break + def meson_func(self) -> str: return CMAKE_TGT_TYPE_MAP.get(self.type.upper()) @@ -171,6 +184,7 @@ class ConverterTarget: mlog.log(' -- install_dir: ', mlog.bold(self.install_dir)) mlog.log(' -- link_libraries: ', mlog.bold(str(self.link_libraries))) mlog.log(' -- link_with: ', mlog.bold(str(self.link_with))) + mlog.log(' -- object_libs: ', mlog.bold(str(self.object_libs))) mlog.log(' -- link_flags: ', mlog.bold(str(self.link_flags))) mlog.log(' -- languages: ', mlog.bold(str(self.languages))) mlog.log(' -- includes: ', mlog.bold(str(self.includes))) @@ -297,11 +311,19 @@ class CMakeInterpreter: self.targets += [ConverterTarget(k)] output_target_map = {x.full_name: x for x in self.targets} + object_libs = [] + # First pass: Basic target cleanup for i in self.targets: i.postprocess(output_target_map, self.src_dir, self.install_prefix) + if i.type == 'OBJECT_LIBRARY': + object_libs += [i] self.languages += [x for x in i.languages if x not in self.languages] + # Second pass: Detect object library dependencies + for i in self.targets: + i.process_object_libs(object_libs) + mlog.log('CMake project', mlog.bold(self.project_name), 'has', mlog.bold(str(len(self.targets))), 'build targets.') def pretend_to_be_meson(self) -> CodeBlockNode: @@ -342,6 +364,14 @@ class CMakeInterpreter: func_n = FunctionNode(self.subdir, 0, 0, name, args_n) return func_n + def method(obj: BaseNode, name: str, args=[], kwargs={}) -> MethodNode: + args_n = ArgumentNode(token()) + if not isinstance(args, list): + args = [args] + args_n.arguments = [nodeify(x) for x in args] + args_n.kwargs = {k: nodeify(v) for k, v in kwargs.items()} + return MethodNode(self.subdir, 0, 0, obj, name, args_n) + def assign(var_name: str, value: BaseNode) -> AssignmentNode: return AssignmentNode(self.subdir, 0, 0, var_name, value) @@ -351,13 +381,19 @@ class CMakeInterpreter: processed = {} def process_target(tgt: ConverterTarget): - # First handle inter dependencies + # First handle inter target dependencies link_with = [] + objec_libs = [] for i in tgt.link_with: assert(isinstance(i, ConverterTarget)) if i.name not in processed: process_target(i) link_with += [id(processed[i.name]['tgt'])] + for i in tgt.object_libs: + assert(isinstance(i, ConverterTarget)) + if i.name not in processed: + process_target(i) + objec_libs += [processed[i.name]['tgt']] # Determine the meson function to use for the build target tgt_func = tgt.meson_func() @@ -379,6 +415,7 @@ class CMakeInterpreter: 'install': tgt.install, 'install_dir': tgt.install_dir, 'override_options': tgt.override_options, + 'objects': [method(id(x), 'extract_all_objects') for x in objec_libs], } # Handle compiler args diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 182326e88..6d268c6cc 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2560,15 +2560,18 @@ external dependencies (including libraries) must go to "dependencies".''') with mlog.nested(): mlog.log('Processing generated meson AST') mlog.log() - mlog.log('=== BEGIN meson.build ===') + + # Debug print the generated meson file + mlog.debug('=== BEGIN meson.build ===') from .ast import AstIndentationGenerator, AstPrinter printer = AstPrinter() ast.accept(AstIndentationGenerator()) ast.accept(printer) printer.post_process() - mlog.log(printer.result) - mlog.log('=== END meson.build ===') - mlog.log() + mlog.debug(printer.result) + mlog.debug('=== END meson.build ===') + mlog.debug() + result = self.do_subproject_meson(dirname, subdir, default_options, required, kwargs, ast, cm_int.bs_files) mlog.log() diff --git a/test cases/cmake/4 object library/main.cpp b/test cases/cmake/4 object library/main.cpp new file mode 100644 index 000000000..f3836087b --- /dev/null +++ b/test cases/cmake/4 object library/main.cpp @@ -0,0 +1,9 @@ +#include +#include "libA.hpp" +#include "libB.hpp" + +using namespace std; + +int main() { + cout << getLibStr() << " -- " << getZlibVers() << endl; +} diff --git a/test cases/cmake/4 object library/meson.build b/test cases/cmake/4 object library/meson.build new file mode 100644 index 000000000..05cd7f719 --- /dev/null +++ b/test cases/cmake/4 object library/meson.build @@ -0,0 +1,14 @@ +project('cmake_object_lib_test', ['cpp']) + +sub_pro = subproject('cmObjLib') +sub_sha = sub_pro.get_variable('lib_sha_dep') +sub_sta = sub_pro.get_variable('lib_sta_dep') + +# Required for the static library +zlib_dep = dependency('zlib') + +exe_sha = executable('shared', ['main.cpp'], dependencies: [sub_sha]) +exe_sta = executable('static', ['main.cpp'], dependencies: [sub_sta, zlib_dep]) + +test('test1', exe_sha) +test('test1', exe_sta) diff --git a/test cases/cmake/4 object library/subprojects/cmObjLib/CMakeLists.txt b/test cases/cmake/4 object library/subprojects/cmObjLib/CMakeLists.txt new file mode 100644 index 000000000..ee9be47e5 --- /dev/null +++ b/test cases/cmake/4 object library/subprojects/cmObjLib/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.7) + +find_package(ZLIB REQUIRED) + +add_library(lib_obj OBJECT libA.cpp libB.cpp) +add_library(lib_sha SHARED $) +add_library(lib_sta STATIC $) + +target_link_libraries(lib_sha ZLIB::ZLIB) +target_link_libraries(lib_sta ZLIB::ZLIB) diff --git a/test cases/cmake/4 object library/subprojects/cmObjLib/libA.cpp b/test cases/cmake/4 object library/subprojects/cmObjLib/libA.cpp new file mode 100644 index 000000000..3736b2c2d --- /dev/null +++ b/test cases/cmake/4 object library/subprojects/cmObjLib/libA.cpp @@ -0,0 +1,5 @@ +#include "libA.hpp" + +std::string getLibStr() { + return "Hello World"; +} diff --git a/test cases/cmake/4 object library/subprojects/cmObjLib/libA.hpp b/test cases/cmake/4 object library/subprojects/cmObjLib/libA.hpp new file mode 100644 index 000000000..58c941321 --- /dev/null +++ b/test cases/cmake/4 object library/subprojects/cmObjLib/libA.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string getLibStr(); diff --git a/test cases/cmake/4 object library/subprojects/cmObjLib/libB.cpp b/test cases/cmake/4 object library/subprojects/cmObjLib/libB.cpp new file mode 100644 index 000000000..b359c298e --- /dev/null +++ b/test cases/cmake/4 object library/subprojects/cmObjLib/libB.cpp @@ -0,0 +1,6 @@ +#include "libB.hpp" +#include + +std::string getZlibVers() { + return zlibVersion(); +} diff --git a/test cases/cmake/4 object library/subprojects/cmObjLib/libB.hpp b/test cases/cmake/4 object library/subprojects/cmObjLib/libB.hpp new file mode 100644 index 000000000..71db6b7a3 --- /dev/null +++ b/test cases/cmake/4 object library/subprojects/cmObjLib/libB.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string getZlibVers();