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



我必须通过外部工具生成源(我从idl文件生成c++类用于fastDDS消息),该工具还生成CMakeLists.txt文件,允许我将生成的文件编译为一个文件。

在我的大超级项目为一个执行目标,我想检查是否存在生成的文件和他们的构建结果。如果& lt; msgs_lib>。a不存在,我要调用生成并构建它

我知道CMake命令add_custom_commandadd_custom_target。但是我不能以正确的方式使用它们,在某些情况下,即使所有的文件都存在,并且它们是按正确的顺序构建的,在某些情况下,什么也不生成(并且在清理之后也没有生成),在某些情况下,exec-target不理解它应该检查并调用generation。

例如,我将在上面写一个案例来开始讨论。我已经简化了很多:

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

项目在一个zip-file:mediaDrive-link

或者这里:

项目目录树:
.
├── 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:

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:

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:

#include "tb_msg.h"
MyClass::MyClass(){};

tb_msg.h:

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

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:

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:

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

在这种情况下,我得到调用scripts/build_msg .sh每次构建,即使libtb_msgs_lib.a存在,并在test_app之前构建。

更多。在add_custom_commandOUTPUT节我把.a,但在最好的情况下,这里应该是dir gen_source/*中的所有文件,但我认为这是另一个问题,我可以在解决主要问题后比特它。

要解决您的问题,我建议不依赖外部工具的cmake脚本,而是管理从IDL文件生成并构建库。我假设您的项目有一个包含IDL文件的文件夹,我们称之为idl。在此文件夹中还放置一个CMakeLists.txt文件,用于生成和构建库。

项目的结构如下:

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

在本例中,idl/Bar.idlidl/Foo.idlidl/MyClass.idl文件可以为空,只有它们的存在才重要。

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_LIST中的每个文件,调用外部工具(GENERATOR来自根CMakeLists.txt)来生成cpph文件。生成的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

这里的变化很小,主要是风格上的。

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;
}

脚本/fastmsg.sh

这是一个真实生成器的仿真器。它接受一个FileName.idl,用一个空的FileName类创建FileName.hFileName.cpp文件。

#!/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

最新更新