Skip to content

Commit

Permalink
add my own wrapper script for building the tools subproject
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitmel committed Dec 27, 2023
1 parent 1358e22 commit 5eda783
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 37 deletions.
36 changes: 9 additions & 27 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/cmake/tools_subproject_wrapper.cmake")
configure_tools_subproject_wrapper()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt")
include("${CMAKE_CURRENT_BINARY_DIR}/tools/targets_info.cmake")

project(stmes LANGUAGES C)

if(POLICY CMP0135)
Expand All @@ -21,7 +26,6 @@ option(FETCHCONTENT_QUIET "" OFF) # Output download progress and other logs
option(FETCHCONTENT_UPDATES_DISCONNECTED "" ON) # Don't check for updates every time

include(FetchContent)
include(ExternalProject)

set(DEPENDENCIES_DIR "" CACHE FILEPATH "The directory in which the dependencies will be downloaded and unpacked")
if(DEPENDENCIES_DIR STREQUAL "")
Expand Down Expand Up @@ -75,16 +79,6 @@ FetchContent_Declare(stm32_mw_usb_host
DOWNLOAD_NAME "stm32_mw_usb_host_v3.3.4.tar.gz"
)

# TODO comments
ExternalProject_Add(tools
PREFIX "${CMAKE_BINARY_DIR}/_deps/tools-prefix"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tools"
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tools"
DOWNLOAD_COMMAND ""
INSTALL_COMMAND "" # An empty string suppresses this step since at least CMake 3.10
BUILD_ALWAYS YES # TODO
)

get_property(project_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(lang IN LISTS project_languages)
foreach(config IN ITEMS "DEBUG" "MINSIZEREL" "RELEASE" "RELWITHDEBINFO")
Expand Down Expand Up @@ -257,19 +251,8 @@ add_executable(firmware)
# This is the correct way of setting the file extension for a binary:
set_target_properties(firmware PROPERTIES PREFIX "" SUFFIX ".elf")

# <https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html>
# TODO: Enable more warnings:
# <https://github.com/embeddedartistry/meson-buildsystem/blob/d4de8c83f97cb6389d9895548b555220f9c56e53/compiler/meson.build#L8-L49>
# <https://github.com/embeddedartistry/meson-buildsystem/blob/d4de8c83f97cb6389d9895548b555220f9c56e53/compiler/cpp/meson.build#L11-L21>
# <https://github.com/embeddedartistry/cmake-buildsystem/blob/f442d5ddbdd87f7590cb06cdbf6c319fa119578e/compiler/DefaultCompilerSettings.cmake#L9-L69>
target_compile_options(firmware PRIVATE
-Wall -Wextra -Wpedantic -pedantic-errors
-Werror=return-type
-Wdouble-promotion
-Wmissing-declarations
-Werror=float-conversion
$<$<COMPILE_LANGUAGE:C>:-Werror=strict-prototypes>
)
include("${CMAKE_CURRENT_LIST_DIR}/cmake/common_flags.cmake")
add_common_flags_to_target(firmware)

target_link_libraries(firmware PUBLIC
stm32f4xx_hal stm32_usb_host FatFs printf m
Expand Down Expand Up @@ -307,9 +290,8 @@ target_link_options(firmware PRIVATE LINKER:--cref,-Map=${linker_map_file})
set_property(TARGET firmware APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${linker_map_file}")

add_dependencies(firmware tools)
set(linker_plugin_file "${CMAKE_CURRENT_BINARY_DIR}/tools/libtest_linker_plugin.so")
target_link_options(firmware PRIVATE LINKER:-plugin,${linker_plugin_file})
set_property(TARGET firmware APPEND PROPERTY LINK_DEPENDS "${linker_plugin_file}")
target_link_options(firmware PRIVATE LINKER:-plugin,${tools__test_linker_plugin__path})
set_property(TARGET firmware APPEND PROPERTY LINK_DEPENDS "${tools__test_linker_plugin__path}")

include(CheckCCompilerFlag)
# A replacement for the CheckLinkerFlag module, added in CMake v3.18, which
Expand Down
18 changes: 18 additions & 0 deletions cmake/common_flags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Configuration of the compilation flags shared between the firmware, the tools
# and other new subprojects potentially required in the future.

function(add_common_flags_to_target target)
# <https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html>
# TODO: Enable more warnings:
# <https://github.com/embeddedartistry/meson-buildsystem/blob/d4de8c83f97cb6389d9895548b555220f9c56e53/compiler/meson.build#L8-L49>
# <https://github.com/embeddedartistry/meson-buildsystem/blob/d4de8c83f97cb6389d9895548b555220f9c56e53/compiler/cpp/meson.build#L11-L21>
# <https://github.com/embeddedartistry/cmake-buildsystem/blob/f442d5ddbdd87f7590cb06cdbf6c319fa119578e/compiler/DefaultCompilerSettings.cmake#L9-L69>
target_compile_options(${target} PRIVATE
-Wall -Wextra -Wpedantic -pedantic-errors
-Werror=return-type
-Wdouble-promotion
-Wmissing-declarations
-Werror=float-conversion
$<$<COMPILE_LANGUAGE:C>:-Werror=strict-prototypes>
)
endfunction()
77 changes: 77 additions & 0 deletions cmake/tools_subproject_wrapper.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# The tools need to be compiled for the host machine using the host C compiler,
# but unfortunately CMake doesn't support mixing multiple different compilers
# in the same project. To remedy this I use an improvised wrapper reminiscent
# of ExternalProject combined with FetchContent: like FetchContent, the
# configuration and build steps of the subproject are performed together with
# the configuration and building of the main project (respectively), but that
# is done through a recursive invocation of CMake and Make, akin to
# ExternalProject, instead of the subproject being added with
# add_subdirectory(), for the ability to mix compilers and toolchains.
function(configure_tools_subproject_wrapper)
set(src_dir "${CMAKE_CURRENT_SOURCE_DIR}/tools")
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/tools")

get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

set(configure_cmd "${CMAKE_COMMAND}" "-S${src_dir}" "-B${build_dir}")

# The logic for passing the generator options was taken from
# <https://gitlab.kitware.com/cmake/cmake/-/blob/v3.28.1/Modules/ExternalProject.cmake#L3740-3809>
# <https://gitlab.kitware.com/cmake/cmake/-/blob/v3.28.1/Modules/FetchContent.cmake#L1585-1605>
list(APPEND configure_cmd "-G${CMAKE_GENERATOR}")
if(CMAKE_GENERATOR_PLATFORM)
list(APPEND configure_cmd "-A${CMAKE_GENERATOR_PLATFORM}")
endif()
if(CMAKE_GENERATOR_TOOLSET)
list(APPEND configure_cmd "-T${CMAKE_GENERATOR_TOOLSET}")
endif()
if(CMAKE_GENERATOR_INSTANCE)
list(APPEND configure_cmd "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
endif()
if(CMAKE_MAKE_PROGRAM)
list(APPEND configure_cmd "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
endif()

# Pass through other relevant variables as well.
if(NOT is_multi_config)
list(APPEND configure_cmd "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}")
endif()
list(APPEND configure_cmd "-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=${CMAKE_EXPORT_COMPILE_COMMANDS}")

# A workaround for weird legacy CMake behavior, see:
# <https://gitlab.kitware.com/cmake/cmake/-/issues/16356>
# <https://gitlab.kitware.com/cmake/cmake/-/issues/21378>
# <https://gitlab.kitware.com/cmake/cmake/-/merge_requests/7108>
# <https://cmake.org/cmake/help/latest/policy/CMP0132.html>
# The code responsible for this:
# <https://gitlab.kitware.com/cmake/cmake/blob/v3.28.1/Source/cmGlobalGenerator.cxx#L793-809>
list(PREPEND configure_cmd "${CMAKE_COMMAND}" -E env --unset=CC --unset=CXX --unset=ASM)

message(STATUS "Configuring tools subproject")
execute_process(
COMMAND ${configure_cmd}
RESULT_VARIABLE cmd_result
)
if(cmd_result)
message(FATAL_ERROR "Configuration of the tools subproject failed: ${cmd_result}")
endif()

# This was shamelessly stolen, errrrm, borrowed from
# <https://gitlab.kitware.com/cmake/cmake/-/blob/v3.28.1/Modules/ExternalProject.cmake#L1928-2019>
if(CMAKE_GENERATOR MATCHES "Make")
# Make is a special case because it supports recursive invocation by design.
set(build_cmd "$(MAKE)" -C "${build_dir}")
else()
set(build_cmd "${CMAKE_COMMAND}" --build "${build_dir}")
if(is_multi_config)
list(APPEND build_cmd --config $<CONFIG>)
endif()
endif()

# This target will always be considered out-of-date and will always be built
# (exactly what we need).
add_custom_target(tools
COMMAND ${build_cmd}
COMMENT "Building tools subproject"
)
endfunction()
21 changes: 11 additions & 10 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.5)
project(stmes_tools C CXX)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include("${CMAKE_CURRENT_LIST_DIR}/../cmake/common_flags.cmake")

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS YES)
Expand All @@ -12,13 +12,14 @@ set(CMAKE_CXX_EXTENSIONS YES)
set(CMAKE_CXX_STANDARD_REQUIRED YES)

add_library(test_linker_plugin SHARED test_linker_plugin.cc)
add_common_flags_to_target(test_linker_plugin)

# TODO: Share this with the top-level CMakeLists.txt somehow
target_compile_options(test_linker_plugin PRIVATE
-Wall -Wextra -Wpedantic -pedantic-errors
-Werror=return-type
-Wdouble-promotion
-Wmissing-declarations
-Werror=float-conversion
$<$<COMPILE_LANGUAGE:C>:-Werror=strict-prototypes>
)
# This file will be included by the top-level CMakeLists.txt to avoid having to
# predict the paths to the tool binaries there. Using the export(TARGETS)
# command won't do because targets, even imported ones, assume that they are
# created for the same platform, which is clearly not the case with the tools
# and the cross-compiled firmware.
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/targets_info.cmake" CONTENT [=[
set(tools__supplement_firmware__path "$<TARGET_FILE:supplement_firmware>")
set(tools__test_linker_plugin__path "$<TARGET_FILE:test_linker_plugin>")
]=])

0 comments on commit 5eda783

Please sign in to comment.