YC Yc.W home Systems · C++ · AI Infrastructure
Developer Tools · Note

CMake OPTION

Explore all Developer Tools notes →

https://clubjuggler.livejournal.com/138364.html

includes a component

As an example, consider a project that optionally includes a component that communicates via USB and allows the user, at compile time, to specify whether to include that component or not. The CMakeLists.txt file to do that looks like this:

PROJECT(myproject)
OPTION(WITH_USB "Include our USB component" OFF)
SET(SRCS file1.c file2.c file3.c)
IF(WITH_USB)
  SET(SRCS ${SRCS} usbfile1.c usbfile2.c)
ENDIF(WITH_USB)
ADD_EXECUTABLE(myproject ${SRCS})

The OPTION(...) line creates a parameter WITH_USB and sets its default value to OFF. CMake also includes a help string to describe what the option does. Based on the value of WITH_USB, the variable SRCS either includes or excludes the two USB-related files usbfile1.c and usbfile2.c. SRCS is then passed to the ADD_EXECUTABLE call to define the program’s source files. To include USB support, simply enable WITH_USB like this: $ cmake -DWITH_USB=ON /path/to/source/files


the optional USB support a library in a subdirectory

PROJECT(myproject)
OPTION(WITH_USB "Include our USB component" OFF)
SET(SRCS file1.c file2.c file3.c)
ADD_EXECUTABLE(myproject ${SRCS})
IF(WITH_USB)
  ADD_SUBDIRECTORY(usblib)
  TARGET_LINK_LIBRARIES(myproject usblib)
ENDIF(WITH_USB)

Given this file, the USB source files would be placed in a subdirectory called usblib along with a new CMakeLists.txt file:

PROJECT(usblib)
SET(SRCS usbfile1.c usbfile2.c)
ADD_LIBRARY(usblib ${SRCS})

Now, if USB support is enabled, CMake builds the USB library and links it into the executable.

But how does the code know to use the optional USB code?

First, the USB-specific code should be surrounded with a #ifdef WITH_USB. Next, CMake processes a special configuration file, substituting placeholders with CMake variables.

Let’s make a new file called config.h.cmake that contains this:

#ifndef TEST_CONFIG_H
#define TEST_CONFIG_H

#cmakedefine WITH_USB

#endif

Then, in the CMakeLists.txt file, modify the first part to look like this:

PROJECT(myproject)
OPTION(WITH_USB "Include our USB component" OFF)
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake 
  ${CMAKE_BINARY_DIR}/config.h)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})

Given this, CMake translates config.h.cmake to create config.h in the build directory. The INCLUDE_DIRECTORIES command tells the compiler to add both the source directory and the build directory to the include path. If WITH_USB is enabled, CMake replaces #cmakedefine WITH_USB with #define WITH_USB. Otherwise, it replaces #cmakedefine WITH_USB with /*#undef WITH_USB*/. As long as you #include config.h and surround the USB code with #ifdef WITH_USB, everything just works. The only downside at the moment is that config.h.cmake must be created manually.


Next → CMake MESSAGE