Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

244
Views
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. 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. 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.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

You already have a src/CMakeLists.txt, so you are part of the way there. Put your overall build settings -- dependencies, C standard version, global compiler flags -- in the top-level CMakeLists.txt. In the subdirectories, put only your CMake commands for the executables, or whatever target makes sense locally.

(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)

Personally, from the minimal sketch of the source layout here, I'd do:

  • src/CMakeLists.txt does an add_subdirectory() command for each board, e.g. add_subdirectory(board/board_a) . If you like, set() a variable to a list of board names and you can iterate over it.
  • In each board's subdirectory, create a library -- shared, static, or OBJECT -- named after the board, with the sources for that board. For instance 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
    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).

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".

over 4 years ago · Santiago Trujillo Report

0

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).

Put CMakeLists.txt inside board_b that does add_library(board_b board.c).

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).
  • Repeat above for exe_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}).

  • Compile your project twice with cmake -DUSE_BOARD=board_a and cmake -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.

Remember to use target_* commands, not the directory specific commands.

over 4 years ago · Santiago Trujillo Report

0

This isn't too bad with object libraries:

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.

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.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!