简体   繁体   English

如何在 CMake 中构建两个共享主 function 的可执行文件?

[英]How can I build two executables that share a main function in CMake?

I have a project that's becoming large enough that I want to switch to from a plain Makefile to CMake.我有一个项目变得足够大,以至于我想从普通的 Makefile 切换到 CMake。 My project contains only one application, but supports two different boards (each board has a set of source files, and some defines specific to the board).我的项目只包含一个应用程序,但支持两个不同的板(每个板都有一组源文件,一些定义特定于板)。 The (simplified) project structure currently looks like this: (简化的)项目结构目前如下所示:

CMakeLists.txt
src/
├─ board/
│  ├─ board_a/
│  │  ├─ board.c
│  ├─ board_b/
│  │  ├─ board.c
├─ app/
│  ├─ main.c
CMakeLists.txt

I could (and currently have) just put everything in the root CMakeLists.txt file, but I don't want that file to become enormous as the project expands.可以(并且目前已经)将所有内容都放在根 CMakeLists.txt 文件中,但我不希望该文件随着项目的扩展而变得庞大。 Essentially, I am wondering how I can create a project which allows me to build an executable for either board where each executable can have a separate set of defines (that are used in both the board.c and main.c files), source files ( board.c in this case, while sharing the main.c ), and can share compile/linker options (I want to share some common compilation settings between both executables) without having one enormous CMakeLists.txt .本质上,我想知道如何创建一个项目,该项目允许我为任一板构建一个可执行文件,其中每个可执行文件可以有一组单独的定义(在board.cmain.c文件中使用),源文件( board.c在这种情况下,同时共享main.c ),并且可以共享编译/链接器选项(我想在两个可执行文件之间共享一些常见的编译设置),而无需一个巨大的CMakeLists.txt

You already have a src/CMakeLists.txt , so you are part of the way there.你已经有一个src/CMakeLists.txt ,所以你是其中的一部分。 Put your overall build settings -- dependencies, C standard version, global compiler flags -- in the top-level CMakeLists.txt .将您的整体构建设置——依赖项、C 标准版本、全局编译器标志——放在顶层CMakeLists.txt中。 In the subdirectories, put only your CMake commands for the executables, or whatever target makes sense locally.在子目录中,只放置可执行文件的 CMake 命令,或任何在本地有意义的目标。

(As an aside, define "enormous"? I've got top-level CMakeLists here that are anywhere between 200-950 lines, but I've seen 3000-line monstrosities as well) (顺便说一句,定义“巨大”?我这里有顶级 CMakeLists,它们介于 200-950 行之间,但我也看到了 3000 行的怪物)

Personally, from the minimal sketch of the source layout here, I'd do:就个人而言,从这里的源布局的最小草图,我会这样做:

  • src/CMakeLists.txt does an add_subdirectory() command for each board , eg add_subdirectory(board/board_a) . src/CMakeLists.txt每个板执行add_subdirectory()命令,例如add_subdirectory(board/board_a) If you like, set() a variable to a list of board names and you can iterate over it.如果您愿意, set()一个变量设置为板名列表,然后您可以对其进行迭代。
  • In each board's subdirectory, create a library -- shared, static, or OBJECT -- named after the board, with the sources for that board.在每个板的子目录中,创建一个以板命名的库——shared、static 或OBJECT以及该板的源代码。 For instance add_library(board_a OBJECT board.c)例如add_library(board_a OBJECT board.c)
  • Back in src/CMakeLists.txt again, for each board, add an executable with the source from app/ and link to the library defined for the board, like再次回到src/CMakeLists.txt ,对于每个板,添加一个可执行文件,其中包含来自app/的源代码,并链接到为板定义的库,例如
    add_executable(exe_board_a app/source.c) target_link_library(exe_board_a PRIVATE board_a)
    If there are special considerations for that executable, set them there as well.如果该可执行文件有特殊注意事项,请将它们也设置在那里。 Compile flags can be obtained from the library targets (use STATIC then, not OBJECT).编译标志可以从库目标中获得(然后使用 STATIC,而不是 OBJECT)。

This moves most of the long-lists-of-sources and potentially compile flags to the per-board CMakeLists.txt and turns the intermediate level into a long list of "make this executable".这将大部分长的源列表和潜在的编译标志移动到每板CMakeLists.txt并将中间级别转换为“使此可执行文件”的长列表。

how I can create a project which allows me to build an executable for either board where each executable can have a separate set of defines我如何创建一个项目,该项目允许我为任一板构建可执行文件,其中每个可执行文件都可以有一组单独的定义

Put CMakeLists.txt inside board_a that does add_library(board_a board.c) .CMakeLists.txt放入执行board_a add_library(board_a board.c)的 board_a 中。

Put CMakeLists.txt inside board_b that does add_library(board_b board.c) .CMakeLists.txt放入执行board_b add_library(board_b board.c)的 board_b 中。

If the boards are somewhat similar:如果板有点相似:

  • In the root CMakeLists.txt create a add_executable(exe_board_a main.c) that target_link_libraries(exe_board_a PUBLIC board_a) .在根CMakeLists.txt创建一个add_executable(exe_board_a main.c)target_link_libraries(exe_board_a PUBLIC board_a)
  • Repeat above for exe_board_bexe_board_b重复上述操作

If the boards are unrelated, like need many different compiler flags or separate toolchain files or even different compilers:如果板子不相关,比如需要许多不同的编译器标志或单独的工具链文件甚至不同的编译器:

  • In the root CMakeLists.txt add_executable(exe main.c) that does target_link_libraries(exe PUBLIC ${USE_BOARD}) .在执行 target_link_libraries( target_link_libraries(exe PUBLIC ${USE_BOARD})的根CMakeLists.txt add_executable(exe main.c)中。

  • Compile your project twice with cmake -DUSE_BOARD=board_a and cmake -DUSE_BOARD=board_b .使用cmake -DUSE_BOARD=board_acmake -DUSE_BOARD=board_b编译您的项目两次。 Use two separate build directories.使用两个单独的构建目录。 The double compilation can be scripted with a custom script, a root custom Makefile, or you can research cmake-presets.双重编译可以使用自定义脚本、根自定义 Makefile 编写脚本,也可以研究 cmake-presets。

Remember to use target_* commands, not the directory specific commands.请记住使用target_*命令,而不是特定于目录的命令。

This isn't too bad with object libraries:这对于 object 库来说还不错:

cmake_minimum_required(VERSION 3.22)
project(boards LANGUAGES C)

add_library(board_a OBJECT src/board_a/board.c)
target_compile_definitions(
  board_a PUBLIC "defines for board_a.c and main.c")

add_library(board_b OBJECT src/board_b/board.c)
target_compile_definitions(
  board_b PUBLIC "defines for board_b.c and main.c")

add_executable(main_a src/app/main.c)
target_link_libraries(main_a PRIVATE board_a)

add_executable(main_b src/app/main.c)
target_link_libraries(main_b PRIVATE board_b)

You could of course move the add_library calls down into subdirectories (via add_subdirectory ), but the trick I'm using here is to put things like defines on as PUBLIC usage requirements for the object libraries, so that they will propagate to main.c when the associated application compiles.您当然可以将 add_library 调用移动到子目录中(通过add_subdirectory ),但我在这里使用的技巧是将定义为 object 库的 PUBLIC 使用要求之类的东西,以便它们传播到 main.c 时相关的应用程序编译。

You would have one add_executable call per board in the top level which you could of course place in a loop if you wind up with many boards.您将在顶层的每个板上有一个add_executable调用,如果您最终使用许多板,您当然可以将其放置在一个循环中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在两个可执行文件之间共享全局变量? - How to share global variables between two executables? 如何使用 CMake 在 android 构建上编译和共享两个 c++ 库 - How to compile and share two c++ libraries on an android build using CMake 仅使用一次 CMake 时,如何使用 2 个不同的 main.cpp 文件制作 2 个不同的可执行文件? - How to make 2 different executables using 2 different main.cpp files when using CMake only once? 切换分支时如何保持CMake构建工件? - How can I keep CMake build artifacts when switching branches? 如何生成可执行文件列表作为单独的 cmake 目标 - How to produce a list of executables as a separate cmake target 如何使用Visual Studio 2012和Intel Compiler XE 2013构建可在Windows XP中运行的可执行文件? - How can I build executables which can be run in Windows XP using Visual Studio 2012 and Intel Compiler XE 2013? CMake:使用静态库在一个项目中构建多个可执行文件 - CMake: Build Multiple Executables in one Project with Static Library CMake项目结构:如何正确合并库并将它们包含在多个可执行文件中 - CMake Project Structure: How do I properly merge libraries together and include them in multiple executables 我如何在我的主要功能介绍中调用我的两个功能? - how can i call my two functions intro my main function? 如何打印主 function 中的数字? - How can I print the numbers in main function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM