简体   繁体   English

如果我必须通过外部工具生成该库的源和 CMakeLists.txt 文件,我如何在 cmake-base 项目中使用库

[英]How can I use library in cmake-base project if sources and CMakeLists.txt file for this library I have to generate by external tool

I have to generate sources by external tool (I generate c++ classes from IDL-files for fastDDS messages), this tool also generate CMakeLists.txt file that allows me to compile generated files to <msgs_lib>.a file.我必须通过外部工具生成源代码(我从 IDL 文件为 fastDDS 消息生成 c++ 个类),该工具还生成 CMakeLists.txt 文件,允许我将生成的文件编译为 <msgs_lib>.a 文件。

In my big superproject for one exec-target I wonna check existence of generated files and their building result.在我的一个执行目标的大型超级项目中,我不会检查生成的文件及其构建结果是否存在。 if <msgs_lib>.a does not exist I wonna call generation and building it.如果 <msgs_lib>.a 不存在,我将调用生成并构建它。

I know about CMake commands add_custom_command and add_custom_target .我知道 CMake 命令add_custom_commandadd_custom_target But I can't use them in proper way, in some cases generation calls even if all files exists and they was built in proper order, in some cases nothing generates (and after cleaning nothing generates too), in some cases exec-target does not understand that it should check and call generation.但是我不能以正确的方式使用它们,在某些情况下,即使所有文件都存在并且它们是按正确的顺序构建的,在某些情况下也不会生成任何内容(并且在清理后也不会生成任何内容),在某些情况下 exec-target 会不明白它应该检查并调用生成。

For example I'll write above one case for starting the discussion.例如我将在上面写一个案例来开始讨论。 I have simplify it a lot:我已经简化了很多:

Project on github: https://github.com/gladijos/test_project github 上的项目: https://github.com/gladijos/test_project

Project in one zip-file: mediaDrive-link一个 zip 文件中的项目: mediaDrive-link

Or right here:或者就在这里:

project directory tree:项目目录树:

.
├── CMakeLists.txt
├── deps
│   ├── gen_deps
│   └── gen_source
│       └── tb_msgs
│           ├── CMakeLists.txt
│           ├── tb_msg.cpp
│           └── tb_msg.h
├── scripts
│   └── build_msgs.sh
└── test_app
    ├── CMakeLists.txt
    └── main.cpp

root-CMakeLists.txt:根-CMakeLists.txt:

cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)

project(test_project LANGUAGES CXX VERSION 0.0.3)

set(TB_MSGS ${CMAKE_HOME_DIRECTORY}/deps/gen_deps/tb_msgs/build/libtb_msgs_lib.a)

add_custom_command(
  OUTPUT ${TB_MSGS}
  WORKING_DIR ${CMAKE_HOME_DIRECTORY}
  COMMAND ${CMAKE_HOME_DIRECTORY}/scripts/build_msgs.sh ${CMAKE_HOME_DIRECTORY}
)
 
add_custom_target(build_dds_msgs
# ALL 
DEPENDS ${TB_MSGS}
)

# apps
add_subdirectory(test_app)
add_dependencies(test_app build_dds_msgs)

tb_msgs CMakeLists.txt: tb_msgs CMakeLists.txt:

cmake_minimum_required(VERSION 3.5.1)

project("tb_lib")

set(CMAKE_CXX_STANDARD 11)

add_library(tb_msgs_lib 
    tb_msg.cpp
)

tb_msg.cpp: tb_msg.cpp:

#include "tb_msg.h"

MyClass::MyClass(){};

tb_msg.h: tb_msg.h:

#pragma once
class MyClass
{
public:
MyClass();
};

build_msgs.sh: build_msgs.sh:

cp -rf $1/deps/gen_source/* $1/deps/gen_deps/;
cd $1/deps/gen_deps/tb_msgs;
mkdir -p  $1/deps/gen_deps/tb_msgs/build;
cd $1/deps/gen_deps/tb_msgs/build;
cmake .. ;
make;

test_app CMakeListst.txt: test_app CMakeListst.txt:

cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)

project(test_app LANGUAGES CXX VERSION 0.0.1)

add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME}
  ${CMAKE_HOME_DIRECTORY}/deps/gen_deps/tb_msgs/build/libtb_msgs_lib.a
  )

test_app main.cpp: test_app main.cpp:

#include "../deps/gen_deps/tb_msgs/tb_msg.h"
int main()
{
    MyClass myClass;
    return 0;
}

In this case I got call to scripts/build_msgs.sh every build, even if libtb_msgs_lib.a exists, and was built before test_app .在这种情况下,我每次构建都会调用 scripts/build_msgs.sh,即使libtb_msgs_lib.a存在,并且是在test_app之前构建的。

More one.就比较单一。 In add_custom_command OUTPUT section I put .a , but in best case here should be all files in dir gen_source/* but i think it another problem and I can bit it after resolving main problem.add_custom_command OUTPUT部分我放了.a ,但在最好的情况下这里应该是 dir gen_source/* 中的所有文件,但我认为这是另一个问题,我可以在解决主要问题后解决它。

To solve your problem, I suggest not relying on a cmake script from an external tool, but instead managing the generation from IDL files and building the library.为了解决您的问题,我建议不要依赖外部工具的 cmake 脚本,而是管理 IDL 文件的生成并构建库。 I assume that your project has a folder with IDL files, let's call it idl .我假设您的项目有一个包含 IDL 文件的文件夹,我们称它为idl In this folder also place a CMakeLists.txt file to generate and build the library.在此文件夹中还放置一个CMakeLists.txt文件以生成和构建库。

The structure of the project becomes as follows:项目结构变成如下:

.
├── CMakeLists.txt
├── idl
│   ├── CMakeLists.txt
│   ├── Bar.idl
│   ├── Foo.idl
│   └── MyClass.idl
├── scripts
│   └── fastmsg.sh
└── test_app
    ├── CMakeLists.txt
    └── main.cpp

In this example, the files idl/Bar.idl , idl/Foo.idl and idl/MyClass.idl can be empty, only their presence is important.在此示例中,文件idl/Bar.idlidl/Foo.idlidl/MyClass.idl可以为空,只有它们的存在很重要。

CMakeLists.txt CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(test_project LANGUAGES CXX VERSION 0.0.3)

set(GENERATOR ${CMAKE_SOURCE_DIR}/scripts/fastmsg.sh)

# apps
add_subdirectory(idl)
add_subdirectory(test_app)

idl/CMakeLists.txt idl/CMakeLists.txt 文件

For each file in the IDL_LIST an external tool ( GENERATOR from root CMakeLists.txt) is called to generate cpp and h files.对于IDL_LIST中的每个文件,都会调用一个外部工具(根 CMakeLists.txt 中的GENERATOR )来生成cpph文件。 The resulting list of cpp files is used to build the build_dds_msgs library.生成的cpp文件列表用于构建build_dds_msgs库。

cmake_minimum_required(VERSION 3.0)

set(IDL_LIST MyClass.idl Foo.idl Bar.idl)

set(IDL_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CPP_DIR ${CMAKE_CURRENT_BINARY_DIR})

foreach(IDL_FILE ${IDL_LIST})
  string(REPLACE ".idl" ".cpp" CPP_FILE ${IDL_FILE})
  string(REPLACE ".idl" ".h"   HDR_FILE ${IDL_FILE})
  list(APPEND CPP_LIST ${CPP_DIR}/${CPP_FILE})
  add_custom_command(
    OUTPUT ${CPP_DIR}/${CPP_FILE} ${CPP_DIR}/${HDR_FILE}
    COMMAND ${GENERATOR} ${IDL_DIR}/${IDL_FILE}
    WORKING_DIRECTORY ${CPP_DIR}
    DEPENDS  ${IDL_DIR}/${IDL_FILE}
    VERBATIM
  )
endforeach()
 
add_library(build_dds_msgs ${CPP_LIST})
target_include_directories(build_dds_msgs PUBLIC ${CPP_DIR})

# Add dependencies on an external instrument, if any.
# target_include_directories(build_dds_msgs PRIVATE include_from_gen)
# target_link_libraries(build_dds_msgs PRIVATE libs_from_gen)

test_app/CMakeLists.txt & test_app/main.cpp test_app/CMakeLists.txt & test_app/main.cpp

The changes here are minimal, mostly stylistic.这里的变化很小,主要是风格上的。

cmake_minimum_required(VERSION 3.0)

project(test_app LANGUAGES CXX VERSION 0.0.1)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} build_dds_msgs)
#include "MyClass.h"

int main()
{
    MyClass myClass;
    return 0;
}

scripts/fastmsg.sh脚本/fastmsg.sh

This is an emulator of a real generator.这是一个真实发电机的模拟器。 It takes a FileName.idl and creates FileName.h and FileName.cpp files with an empty FileName class.它采用FileName.idl并创建FileName.hFileName.cpp文件, FileName名为空 class。

#!/bin/bash

if [ -z "$1" ]
then
  echo "Usage: `basename $0` filename"
  exit 1
fi


FILE=$(basename -- "$1")
CLASS=${FILE%.*}

cat > $CLASS.h <<EndHpp
#pragma once

class $CLASS
{
public:
    $CLASS();
};
EndHpp

cat > $CLASS.cpp <<EndCpp
#include "$CLASS.h"

$CLASS::$CLASS(){};
EndCpp

exit 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM