Reputation: 2085
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})
the first line's set
command just defines HEADER_DIR
. This is easy.
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?
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.
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
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
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 asadd_executable()
oradd_library()
and must not be anIMPORTED
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