Taylor
Taylor

Reputation: 2085

verifying my understanding of a CMakeLists.txt file

I successfully played trial-and-error with a CMakeLists.txt file, and now everything builds. However, I want to make sure my understanding is correct about how it's working.

I have a project with the following structure:

./
├── bin
├── CMakeLists.txt
├── include
│   └── sql-writer
│       ├── credentials.h
│       ├── database.h
│       ├── datetime.h
│       ├── market_bar.h
│       └── writer.h
├── README.md
├── src
│   ├── CMakeLists.txt
│   ├── database.cpp
│   ├── main.cpp
│   └── writer.cpp
└── test
    ├── CMakeLists.txt
    ├── test-main.cpp
    ├── test_sym_table_pairs
    └── writer_tests.cpp

This builds an executable, a static library, and a test executable. The problem was src/CMakeLists.txt:

set(HEADER_DIR ${sql-writer_SOURCE_DIR}/include/sql-writer)

add_executable(sql-writer-demo main.cpp ${HEADER_DIR})
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) #!
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})

file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
file(GLOB HEADERS ${HEADER_DIR}/*.h)
add_library(sql-writer-lib ${HEADERS} ${SOURCES})
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
  1. the first line's set command just defines HEADER_DIR. This is easy.

  2. target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) must be included after the first add_execuable because otherwise header files will need to be included with relative paths. Is that right? Why does it come after? I've heard cmake treats include directories as "separate" from "sources" (cmake sources not .cpp files). What does that mean?

  3. target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_executable(sql-writer-demo main.cpp ${HEADER_DIR}) as well, and it tells how to link to other libraries.

  4. file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp) is not recomended before only because the directory/file structure could change, and then this wouldn't work anymore

  5. target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_library(sql-writer-lib ${HEADERS} ${SOURCES}) because the compulation of my library sql-writer-lib needs to use other libs, and this is where we tell cmake to look out for those.

Upvotes: 1

Views: 142

Answers (1)

Evg
Evg

Reputation: 26342

  • You typically don't include headers into add_executable and add_library, but only implementation files:

    add_executable(sql-writer-demo main.cpp)
    add_library(sql-writer-lib ${SOURCES})
    
  • add_executable and add_library create a target, target_include_directories specifies include directories for this target. The documentation is pretty clear:

    The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED target.

  • If you use target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR}) with PUBLIC specifier, you don't need to use target_include_directories to specify include directories for targets that link against that library, because the dependency will be propagated automatically. The same applies to target_link_libraries.

So, src/CMakeLists.txt

file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
add_library(sql-writer-lib ${SOURCES})
target_link_libraries(sql-writer-lib PUBLIC mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})

add_executable(sql-writer-demo main.cpp)
target_link_libraries(sql-writer-demo sql-writer-lib)

should work. Whether you want to use PUBLIC on mysqlcppconn ${Boost_LIBRARIES} depends on the structure of your project. I specified it as an example only.

Upvotes: 2

Related Questions