【问题标题】:CMake: Compilation producing an executable and linkable libraryCMake:编译生成可执行和可链接库
【发布时间】:2021-10-18 21:26:03
【问题描述】:

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

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

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

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

本例中的“库”只是包含一些类的头文件和源文件,这些类本身依赖于其他一些库。 (确切地说,是 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文件

希望这已经足够清楚了,但这大概是一件不平凡的事情。

【问题讨论】:

    标签: c++ cmake linker


    【解决方案1】:

    第一个组件:它本身就是一个可执行程序。由 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 文档),但我认为没有理由这样做。

    【讨论】:

    • 感谢您的回答,这看起来可行,虽然我还没有实现它。您在最后的注释中推荐您的建议参考吗?这是我以前从未见过的所有新东西
    • Do you recommend any reference for your suggestions in the notes at the end?在网上搜索“cmake最佳实践”发现:pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-rightgist.github.com/mbinna/…等..
    • 再次跟进:我已按照您的说明构建了第一个组件和相关的库。我在与可执行文件相同的./build 目录中有一个 libXXX.a 文件。如果我想在不同的目录中构建第二个组件,那么我如何告诉 cmake 它应该在哪里查找文件 libXXX.a ?
    • If I want to build the second component in a different directory stackoverflow.com/questions/13556885/… how do I tell cmake CMake 已经知道了,不要告诉 cmake,只需 target_link_libraries。如果libXXX.a 是必须包含在项目中的外部实体,则在这种情况下使用add_library(... IMPORTED)
    猜你喜欢
    • 2013-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多