Search code examples
gcccmakearmstatic-librariesmicrocontroller

CMAKE: How can you prevent CMAKE from building libraries that the project does not depend on?


I am setting up a CMAKE project to build for an ARM target. The project contains a sub-module with the provided SDK for the target. I've created a static library definition for each of the drivers in the sdk with the correct dependencies. Separate library definitions are desirable to prevent bloating the object file with unnecessary code/drivers. The CMakeLists.txt file in the sdk sub-module:

#############################
###### System Library #######
#############################

### System ###
add_library(S32K-SDK-SYSTEM STATIC)

## Headers ##
target_include_directories(S32K-SDK-SYSTEM PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices/common"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices/${CPU}/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices/${CPU}/startup"
)

## Sources ##
file(GLOB SYSTEM-SOURCES -CONFIGURE_DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices/${CPU}/startup/*.c"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/devices/*.c"
)

target_sources(S32K-SDK-SYSTEM PUBLIC
    ${SYSTEM-SOURCES}
)


#############################
######### Drivers ###########
#############################

###########
### ADC ###
###########
add_library(S32K-SDK-ADC-DRIVER STATIC)

## Dependencies ##
target_link_libraries(S32K-SDK-ADC-DRIVER PRIVATE
    S32K-SDK-SYSTEM
    S32K-SDK-CLOCK-DRIVER
)

## Headers ##
target_include_directories(S32K-SDK-ADC-DRIVER PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/inc"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/adc"
)

## Sources ##
file(GLOB_RECURSE ADC-DRIVER-SOURCES -CONFIGURE_DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/adc/*.c"
)

target_sources(S32K-SDK-ADC-DRIVER PUBLIC
    ${ADC-DRIVER-SOURCES}
)


#############
### Clock ###
#############
add_library(S32K-SDK-CLOCK-DRIVER STATIC)

## Dependencies ##
target_link_libraries(S32K-SDK-CLOCK-DRIVER PRIVATE
    S32K-SDK-SYSTEM
    S32K-SDK-INTERRUPT-DRIVER
)

## Headers ##
target_include_directories(S32K-SDK-CLOCK-DRIVER PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/inc"
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/clock/S32K1xx"
)

## Sources ##
file(GLOB_RECURSE CLOCK-DRIVER-SOURCES -CONFIGURE_DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/clock/*.c"
)

target_sources(S32K-SDK-CLOCK-DRIVER PUBLIC
    ${CLOCK-DRIVER-SOURCES}
)


##################
### Comparator ###
##################
add_library(S32K-SDK-COMPARATOR-DRIVER STATIC)

## Dependencies ##
target_link_libraries(S32K-SDK-COMPARATOR-DRIVER PRIVATE
    S32K-SDK-SYSTEM
)

## Headers ##
target_include_directories(S32K-SDK-COMPARATOR-DRIVER PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/inc"
)

## Sources ##
file(GLOB_RECURSE COMPARATOR-DRIVER-SOURCES -CONFIGURE_DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/cmp/*.c"
)

target_sources(S32K-SDK-COMPARATOR-DRIVER PUBLIC
    ${COMPARATOR-DRIVER-SOURCES}
)


###########
### CRC ###
###########
add_library(S32K-SDK-CRC-DRIVER STATIC)

## Dependencies ##
target_link_libraries(S32K-SDK-CRC-DRIVER PRIVATE
    S32K-SDK-SYSTEM
)

## Headers ##
target_include_directories(S32K-SDK-CRC-DRIVER PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/inc"
)

## Sources ##
file(GLOB_RECURSE CRC-DRIVER-SOURCES -CONFIGURE_DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/platform/drivers/src/crc/*.c"
)

target_sources(S32K-SDK-CRC-DRIVER PUBLIC
    ${CRC-DRIVER-SOURCES}
)

etc... 

The sample project contains a single main.c file with the contents:

int main(void) {}

I have configured the "target_link_librarires" in the project's CMakeLists.txt file so that the project only depends on the "system" library (minimal code and register definitions required to create an executable for the target).

cmake_minimum_required(VERSION 3.16)

# CMake Modules Path
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# Toolchain
set(Toolchain "${CMAKE_CURRENT_SOURCE_DIR}/toolchain")
include(toolchain)

# Project Name
project(Template VERSION 1.0)

# C++ Standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
enable_language(ASM)

# Linker Configuration
set(LINKER_SCRIPT "${PROJECT_SOURCE_DIR}/config/S32K142_32_flash.ld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  -T ${LINKER_SCRIPT}  -Xlinker  -Map=${CMAKE_PROJECT_NAME}.map")


###############################
### Processor Configuration ###
###############################

# Define the processor.
set(CPU S32K142)

# Define the core.
if (${CPU} MATCHES "^S32K11")
    message(STATUS "M0+ core.")
    set(CORE M0+)
else ()
    message(STATUS "M4 core.")
    set(CORE M4)
endif()

# TODO Add Definitons
add_definitions(-DCPU_${CPU})

# Specify Compiler Flags
set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -mthumb  -funsigned-char  -funsigned-bitfields  -fshort-enums  -ffunction-sections  -fdata-sections  -fno-jump-tables  -g  -mfloat-abi=hard  -Wall  -Wextra  -Wstrict-prototypes  -Wunused  -Wsign-compare")
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -mthumb  -funsigned-char  -funsigned-bitfields  -fshort-enums  -ffunction-sections  -fdata-sections  -fno-jump-tables  -g  -mfloat-abi=hard  -Wall  -Wextra  -Wstrict-prototypes  -Wunused  -Wsign-compare")


if(${CPU} MATCHES "^S32K11")
    message(STATUS "M0+ core detected.")
    set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS}  -mcpu=cortex-m0 ")
    set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS}  -mcpu=cortex-m0 ")
else()
    message(STATUS "M4 core detected.")
    # TODO Should we override the default fpu option?
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -mcpu=cortex-m4  -mfpu=fpv4-sp-d16")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -mcpu=cortex-m4  -mfpu=fpv4-sp-d16")
endif()


# Executeable
add_executable(${PROJECT_NAME}.elf)

# Add Libraries
add_subdirectory(${PROJECT_SOURCE_DIR}/lib/sdk sdk)

target_link_libraries(${PROJECT_NAME}.elf PUBLIC
    S32K-SDK-SYSTEM
)

target_include_directories(${PROJECT_NAME}.elf PRIVATE
    "${PROJECT_SOURCE_DIR}/include"
)

target_sources(${PROJECT_NAME}.elf PUBLIC
    "${PROJECT_SOURCE_DIR}/src/main.c"
    "${PROJECT_SOURCE_DIR}/startup/startup_S32K142.S"
)

add_custom_command(TARGET ${PROJECT_NAME}.elf
    POST_BUILD
    COMMAND ${CMAKE_OBJCOPY} -O ihex ${PROJECT_NAME}.elf ${PROJECT_NAME}.hex
)

When the project builds it correctly builds the system library and links the target executable, but then proceeds to build all of the defined drivers in the SDK which are obviously not needed if the target executable has already been linked.

$ cmake -G "MinGW Makefiles" .. && /c/MinGW/bin/mingw32-make.exe
-- The C compiler identification is GNU 9.3.1
-- The CXX compiler identification is GNU 9.3.1
-- Check for working C compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe
-- Check for working C compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-g++.exe
-- Check for working CXX compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-g++.exe - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The ASM compiler identification is GNU
-- Found assembler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe
-- M4 core.
-- M4 core detected.
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/Jon/src/S32K-Template/build
Scanning dependencies of target S32K-SDK-SYSTEM
[  1%] Building C object sdk/CMakeFiles/S32K-SDK-SYSTEM.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
[  1%] Building C object sdk/CMakeFiles/S32K-SDK-SYSTEM.dir/platform/devices/startup.c.obj
[  2%] Linking C static library libS32K-SDK-SYSTEM.a
[  2%] Built target S32K-SDK-SYSTEM
Scanning dependencies of target Template.elf
[  2%] Building C object CMakeFiles/Template.elf.dir/src/main.c.obj
[  3%] Building ASM object CMakeFiles/Template.elf.dir/startup/startup_S32K142.S.obj
[  3%] Building C object CMakeFiles/Template.elf.dir/lib/sdk/platform/devices/S32K142/startup/system_S32K142.c.obj
[  4%] Building C object CMakeFiles/Template.elf.dir/lib/sdk/platform/devices/startup.c.obj
[  5%] Linking C executable Template.elf
[  5%] Built target Template.elf
Scanning dependencies of target S32K-SDK-COMPARATOR-DRIVER
[  5%] Building C object sdk/CMakeFiles/S32K-SDK-COMPARATOR-DRIVER.dir/platform/drivers/src/cmp/cmp_driver.c.obj
[  6%] Building C object sdk/CMakeFiles/S32K-SDK-COMPARATOR-DRIVER.dir/platform/drivers/src/cmp/cmp_hw_access.c.obj
[  7%] Building C object sdk/CMakeFiles/S32K-SDK-COMPARATOR-DRIVER.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
[  7%] Building C object sdk/CMakeFiles/S32K-SDK-COMPARATOR-DRIVER.dir/platform/devices/startup.c.obj
[  8%] Linking C static library libS32K-SDK-COMPARATOR-DRIVER.a
[  8%] Built target S32K-SDK-COMPARATOR-DRIVER
Scanning dependencies of target S32K-SDK-INTERRUPT-DRIVER
[  8%] Building C object sdk/CMakeFiles/S32K-SDK-INTERRUPT-DRIVER.dir/platform/drivers/src/interrupt/interrupt_manager.c.obj
[  9%] Building C object sdk/CMakeFiles/S32K-SDK-INTERRUPT-DRIVER.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
[ 10%] Building C object sdk/CMakeFiles/S32K-SDK-INTERRUPT-DRIVER.dir/platform/devices/startup.c.obj
[ 10%] Linking C static library libS32K-SDK-INTERRUPT-DRIVER.a
[ 10%] Built target S32K-SDK-INTERRUPT-DRIVER
Scanning dependencies of target S32K-SDK-CLOCK-DRIVER
[ 11%] Building C object sdk/CMakeFiles/S32K-SDK-CLOCK-DRIVER.dir/platform/drivers/src/clock/S32K1xx/clock_S32K1xx.c.obj
[ 11%] Building C object sdk/CMakeFiles/S32K-SDK-CLOCK-DRIVER.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
[ 12%] Building C object sdk/CMakeFiles/S32K-SDK-CLOCK-DRIVER.dir/platform/devices/startup.c.obj
[ 12%] Building C object sdk/CMakeFiles/S32K-SDK-CLOCK-DRIVER.dir/platform/drivers/src/interrupt/interrupt_manager.c.obj
[ 13%] Linking C static library libS32K-SDK-CLOCK-DRIVER.a
[ 13%] Built target S32K-SDK-CLOCK-DRIVER
Scanning dependencies of target S32K-SDK-ADC-DRIVER
[ 13%] Building C object sdk/CMakeFiles/S32K-SDK-ADC-DRIVER.dir/platform/drivers/src/adc/adc_driver.c.obj
[ 14%] Building C object sdk/CMakeFiles/S32K-SDK-ADC-DRIVER.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
[ 14%] Building C object sdk/CMakeFiles/S32K-SDK-ADC-DRIVER.dir/platform/devices/startup.c.obj
[ 15%] Building C object sdk/CMakeFiles/S32K-SDK-ADC-DRIVER.dir/platform/drivers/src/clock/S32K1xx/clock_S32K1xx.c.obj
[ 15%] Linking C static library libS32K-SDK-ADC-DRIVER.a
[ 15%] Built target S32K-SDK-ADC-DRIVER
etc...

Is there a way to configure CMAKE to not build libraries that project does not depend on? Is there a better way to setup the project to prevent this?


Solution

  • The solution appears to be to specify the "target" argument. Thank's @Stephen Newell.

    $ cmake -G "MinGW Makefiles" ..  && cmake --build . --target Template.elf
    -- The C compiler identification is GNU 9.3.1
    -- The CXX compiler identification is GNU 9.3.1
    -- Check for working C compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe
    -- Check for working C compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe - works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-g++.exe
    -- Check for working CXX compiler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-g++.exe - works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- The ASM compiler identification is GNU
    -- Found assembler: C:/Users/Jon/src/S32K-Template/toolchain/windows/bin/arm-none-eabi-gcc.exe
    -- M4 core.
    -- S32K-SDK OSIF FreeRTOS Enabled
    -- Configuring done
    -- Generating done
    -- Build files have been written to: C:/Users/Jon/src/S32K-Template/build
    Scanning dependencies of target S32K-SDK-SYSTEM
    [ 33%] Building C object sdk/CMakeFiles/S32K-SDK-SYSTEM.dir/platform/devices/S32K142/startup/system_S32K142.c.obj
    [ 33%] Building C object sdk/CMakeFiles/S32K-SDK-SYSTEM.dir/platform/devices/startup.c.obj
    [ 33%] Linking C static library libS32K-SDK-SYSTEM.a
    [ 33%] Built target S32K-SDK-SYSTEM
    Scanning dependencies of target Template.elf
    [ 33%] Building C object CMakeFiles/Template.elf.dir/src/main.c.obj
    [ 33%] Building ASM object CMakeFiles/Template.elf.dir/startup/startup_S32K142.S.obj
    [ 66%] Building C object CMakeFiles/Template.elf.dir/lib/sdk/platform/devices/S32K142/startup/system_S32K142.c.obj
    [ 66%] Building C object CMakeFiles/Template.elf.dir/lib/sdk/platform/devices/startup.c.obj
    [100%] Linking C executable Template.elf
    [100%] Built target Template.elf