首页 > 解决方案 > CMake:编译生成可执行和可链接库

问题描述

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

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

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

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

我想要做的是以某种方式让 CMake 编译“第一个组件”并生成一个或多个目标文件,我可以在“第二个组件”中链接到(再次使用 CMake)。

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

我确信必须有可能让 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还没有产生它们。

我不知道该怎么做:

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

标签: c++cmakelinker

解决方案


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

推荐阅读