CMake:生成可执行和可链接库的编译



我真的不知道如何准确地表达这个问题,但这是我最好的尝试…

我最近开始从事一个大型项目,我想把它分成几个组成部分。

下面是其中两个组件的工作原理:

  • 第一个组件:它本身是一个可执行程序。由CMake制作。获取一些库代码的源文件,并与main.cpp文件进行编译和链接。
  • 第二个组件:应该使用在第一个组件中编译的相同的库,但使用不同的main.cpp文件,加上一些新的库。

"libraries"在这种情况下,只有头文件和源文件,其中包含一些类,这些类本身依赖于其他一些库。(确切地说是SDL)

我想做的是让CMake编译"第一组件"并产生一个或多个对象文件,我可以链接到(再次使用CMake)在"第二组件"。

我希望这是有意义的,但它可能不是很明显,所以这里有一些进一步的细节:

  • 第一个组件使用SDL渲染和绘制文本到SDL窗口。我编写的各种类做了很多事情,包括从文件中加载字体,在系统中查找字体,以及管理SDL对象(如窗口和呈现的文本对象)。main.cpp文件仅用于测试目的。它允许编译一个可执行文件,证明一切都按预期工作。如果您愿意,可以将其视为测试驱动的开发文件,尽管它不包含任何正式的测试。

  • 第二个组件依赖于gcc/g++通常会在编译第一个组件时生成的目标文件。换句话说,我希望能够从第一个组件中获取一些对象文件,并使用它们来编译第二个组件。我可以将源文件从第一个组件复制粘贴到第二个组件,然后从头开始编译,但这会弄乱我的git存储库,而且效率也不是特别高。

我相信它必须有可能得到cmake从第一个组件产生一些对象文件,然后在编译第二个组件时链接那些。当然,它可能需要两个独立的cmake进程,但这没有关系。

请注意;我不想编译共享对象。我假设我想静态地链接我的目标文件,但是我假设默认情况下cmake将调用一个动态链接进程。换句话说,SDL库仍然应该是动态链接的。我自己的库不应该动态链接,因为它们在linux系统上不可用,它们只在我自己的linux系统上可用。

最小工作示例?

这是一种MWE有点毫无意义的事情,但这里仍然是一个尝试。

第一个目录是这样设置的

first/
main.cpp
first.h
first.cpp
CMakeLists.txt
build [d]

第二个目录只包含一个main.cpp文件。

CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
project(testproject)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
find_package(SDL2 REQUIRED)
include_directories(testproject ${SDL2_INCLUDE_DIRS})
set(SOURCE_FILES main.cpp first.cpp)
add_executable(testproject ${SOURCE_FILES})
target_link_libraries(testproject ${SDL2_LIBRARIES})

main.cpp:
#include "first.h"
int main()
{
SDL_Init(SDL_INIT_VIDEO);
// using first library in main function
SDL_Window *window = GetWindow();
// doesn't draw anything, but you can
// press the window X to quit
for(bool quit = false; quit == false; )
{
SDL_Event event;
while(SDL_PollEvent(&event) != 0)
{
if(event.type == SDL_QUIT)
{
quit = true;
}
}
}
FreeWindow(window);
SDL_Quit();
return 0;
}

first.h:
#ifndef FIRST_H
#define FIRST_H
#include <SDL2/SDL.h>
SDL_Window* GetWindow();
void FreeWindow(SDL_Window* &window);
#endif // FIRST_H

first.cpp
#include "first.h"
SDL_Window* GetWindow()
{
SDL_Window *window =
SDL_CreateWindow(
"a test window",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
800, 600, SDL_WINDOW_SHOWN);
return window;
}

void FreeWindow(SDL_Window *&window)
{
SDL_DestroyWindow(window);
window = nullptr;
}

这是个有点奇怪的例子。我试图包含一些非常小的函数,这些函数会产生一个目标文件,并利用外部SDL库。在这种情况下,第二个文件夹可以只是main.cpp的一个副本,一个头文件的副本,或者CMakeLists.txt中的一行,告诉make系统在哪里找到头文件,然后它应该有一些方法来找到目标文件,这些文件目前不存在,因为第一个CMakeLists.txt还没有产生它们。

我不知道怎么做的事情:

  • 告诉目录中的cmake首先生成一个包含库代码的(理想情况下是一个)目标文件的目录,但不包含main.cpp的目标代码
  • 告诉cmake在第二个目录中头文件首先在
  • 告诉第二个目录中的cmake,该目录首先生成的库代码的目标文件所在的目录,然后如何将其链接到第二个目录中的新main.cpp文件

希望这是足够清楚的,但这可能是一个不平凡的事情。

第一个组件:本身是一个可执行程序。由CMake制作。获取库代码的一些源文件,并使用main.cpp文件。

第二个组件:应该使用相同的库在第一个组件中编译,但另加一个不同的main.cpp文件一些新的图书馆

就:

find_library(SDL2 REQUIRED)
add_library(common_stuff some_source_files_for_library_code)
target_link_libraries(common_stuff PUBLIC
SDL2::SDL2    # prefer newer INTERFACE libraries **if available**
)
target_include_directories(common_stuff PUBLIC 
${CMAKE_CURRENT_SOURCE_DIR}
)
add_executable(first_component main.cpp)
target_link_libraries(first_component PRIVATE common_stuff)
add_library(second_component different_main.cpp)
target_link_libraries(second_component PUBLIC common_stuff)

指出:

  • 喜欢不是使用set(CMAKE_... ...)。例如,target_compile_features优于set(CMAKE_CXX_STANDARD 14)
  • common_stuff可以OBJECT库(参见add_library文档),但我认为没有理由。

最新更新