簡體   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

我必須通過外部工具生成源代碼(我從 IDL 文件為 fastDDS 消息生成 c++ 個類),該工具還生成 CMakeLists.txt 文件,允許我將生成的文件編譯為 <msgs_lib>.a 文件。

在我的一個執行目標的大型超級項目中,我不會檢查生成的文件及其構建結果是否存在。 如果 <msgs_lib>.a 不存在,我將調用生成並構建它。

我知道 CMake 命令add_custom_commandadd_custom_target 但是我不能以正確的方式使用它們,在某些情況下,即使所有文件都存在並且它們是按正確的順序構建的,在某些情況下也不會生成任何內容(並且在清理后也不會生成任何內容),在某些情況下 exec-target 會不明白它應該檢查並調用生成。

例如我將在上面寫一個案例來開始討論。 我已經簡化了很多:

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

一個 zip 文件中的項目: 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

根-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_msgs.sh,即使libtb_msgs_lib.a存在,並且是在test_app之前構建的。

就比較單一。 add_custom_command OUTPUT部分我放了.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中的每個文件,都會調用一個外部工具(根 CMakeLists.txt 中的GENERATOR )來生成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.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