-
Notifications
You must be signed in to change notification settings - Fork 198
/
mission_build.cmake
395 lines (336 loc) · 16.1 KB
/
mission_build.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
##################################################################
#
# cFS project top-level mission build recipes
#
# This manages the overall top-level build environment
#
# Note that the target CPUs may use different architectures, therefore each
# architecture must be done as a separate sub-build since none of the binaries
# can be shared.
#
# This is a normal (non-cross) build recipe and a custom target
# is generated per-cpu which is typically a cross (arch-specific) build.
#
# In addition to those custom targets, targets for tools that execute directly
# on the development host may also be created via this recipe.
#
##################################################################
##################################################################
#
# FUNCTION: initialize_globals
#
# Set up global mission configuration variables.
# In the top level mode (this file)t reads extracts state info from
# configuration files within the project source tree (the _defs directory)
#
function(initialize_globals)
# Entry point for the "mission" (top level) build
# Determine the values for the cache variables
if (NOT DEFINED MISSION_BINARY_DIR)
set(MISSION_BINARY_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Top level mission binary directory")
endif (NOT DEFINED MISSION_BINARY_DIR)
# this is the parent (mission) build and variable values must be determined
# Obtain the "real" top-level source directory and set it in parent scope
if (NOT DEFINED MISSION_SOURCE_DIR)
get_filename_component(MISSION_SOURCE_DIR "${CFE_SOURCE_DIR}/.." ABSOLUTE)
set(MISSION_SOURCE_DIR ${MISSION_SOURCE_DIR} CACHE PATH "Top level mission source directory")
endif(NOT DEFINED MISSION_SOURCE_DIR)
# The configuration should be in a subdirectory named "<mission>_defs". If there is one
# and only one of these, this is assumed to be it. If there is more than one then the
# user MUST specify which one is intended to be used by setting MISSIONCONFIG in the environment
if (NOT MISSIONCONFIG)
set(MCTEMP $ENV{MISSIONCONFIG})
if ("${MCTEMP}" STREQUAL "")
file(GLOB DEFDIRS RELATIVE "${MISSION_SOURCE_DIR}" "${MISSION_SOURCE_DIR}/*_defs")
list(LENGTH DEFDIRS DDLEN)
if (NOT DDLEN EQUAL 1)
message(FATAL_ERROR "Unable to automatically determine the mission config directory. Specify it with the MISSIONCONFIG variable.")
endif (NOT DDLEN EQUAL 1)
string(REPLACE "_defs" "" MCTEMP ${DEFDIRS})
message(STATUS "Mission configuration ${MCTEMP} automatically selected")
endif ("${MCTEMP}" STREQUAL "")
# Set the MISSIONCONFIG as a CMake cache variable so it will be preserved for future runs
set(MISSIONCONFIG ${MCTEMP} CACHE STRING "Mission configuration selection")
unset(MCTEMP)
endif(NOT MISSIONCONFIG)
# Cache the values of certain environment variables used during the setup process
# The issue with environment variables is that they are transient and may change at any time,
# such as if the build is invoked from a different shell. Whenever the build system is regenerated
# in the future, we need to use the same values for these options even if the user has modified them
# in the local environment.
set(SIMULATION $ENV{SIMULATION} CACHE STRING "Enable simulation mode using specified toolchain")
set(ENABLE_UNIT_TESTS $ENV{ENABLE_UNIT_TESTS} CACHE BOOL "Enable build of unit tests")
# Export values to parent level
set(MISSION_DEFS ${MISSION_SOURCE_DIR}/${MISSIONCONFIG}_defs CACHE PATH "Full path to mission definitions directory")
endfunction(initialize_globals)
##################################################################
#
# FUNCTION: add_static_dependencies
#
# Adds an entry to the depedency list during app search
# (Note apps can depend on other apps/libs)
#
function(add_static_dependencies TGT_DEPS)
set(FULLDEPS ${MISSION_DEPS} ${FIND_DEP_LIST})
set(NEWDEPS)
foreach(DEP ${TGT_DEPS} ${ARGN})
list(FIND FULLDEPS ${DEP} DEPIDX)
if (DEPIDX LESS 0)
list(APPEND NEWDEPS ${DEP})
list(APPEND FULLDEPS ${DEP})
endif()
endforeach()
set(FIND_DEP_LIST ${FIND_DEP_LIST} ${NEWDEPS} PARENT_SCOPE)
endfunction(add_static_dependencies)
##################################################################
#
# FUNCTION: prepare
#
# Called by the top-level CMakeLists.txt to set up prerequisites
#
function(prepare)
# Propagate the SIMULATION variable if set
if (SIMULATION)
add_definitions(-DSIMULATION=${SIMULATION})
endif (SIMULATION)
# Generate the cfe_mission_cfg.h wrapper file
generate_config_includefile("inc/cfe_mission_cfg.h" mission_cfg.h ${MISSIONCONFIG})
generate_config_includefile("inc/cfe_perfids.h" perfids.h ${MISSIONCONFIG} )
# Create custom targets for building and cleaning all architectures
# This is required particularly for doing extra stuff in the clean step
add_custom_target(mission-all COMMAND $(MAKE) all)
add_custom_target(mission-install COMMAND $(MAKE) install)
add_custom_target(mission-clean COMMAND $(MAKE) clean)
add_custom_target(mission-prebuild)
# Locate the source location for all the apps found within the target file
# This is done by searching through the list of paths to find a matching name
# The environment variable is cached so it will be retained across runs.
set(CFS_APP_PATH "$ENV{CFS_APP_PATH}"
CACHE STRING "Extra search path for code modules"
)
string(REPLACE ":" ";" CFS_APP_PATH "${CFS_APP_PATH}")
set(MISSION_MODULE_SEARCH_PATH ${CFS_APP_PATH} ${MISSION_MODULE_SEARCH_PATH})
set(MISSION_DEPS "cfe-core" "osal" ${MISSION_CORE_MODULES})
set(APP_MISSING_COUNT 0)
message(STATUS "Search path for modules: ${MISSION_MODULE_SEARCH_PATH}")
# Now search for the rest of CFS applications/libraries/modules - these may exist in
# any directory within the search path.
foreach(APP ${MISSION_APPS} ${MISSION_DEPS} ${MISSION_PSPMODULES})
set (APPFOUND FALSE)
foreach(APPSRC ${MISSION_MODULE_SEARCH_PATH} ${${APP}_SEARCH_PATH})
if (NOT IS_ABSOLUTE "${APPSRC}")
set(APPSRC "${MISSION_SOURCE_DIR}/${APPSRC}")
endif()
if(IS_DIRECTORY "${APPSRC}/${APP}")
set(APPFOUND "${APPSRC}/${APP}")
break()
endif()
endforeach()
if (APPFOUND)
get_filename_component(${APP}_MISSION_DIR "${APPFOUND}" ABSOLUTE)
include("${APPFOUND}/mission_build.cmake" OPTIONAL)
message(STATUS "Module '${APP}' found at ${${APP}_MISSION_DIR}")
else()
message("** Module ${APP} NOT found **")
math(EXPR APP_MISSING_COUNT "${APP_MISSING_COUNT} + 1")
endif()
endforeach()
if (APP_MISSING_COUNT GREATER 0)
message(FATAL_ERROR "Target build incomplete, source for ${APP_MISSING_COUNT} module(s) not found.")
endif (APP_MISSING_COUNT GREATER 0)
# Export the full set of dependencies to the parent build
# including the individual dependency paths to each component
set(MISSION_DEPS ${MISSION_DEPS} PARENT_SCOPE)
foreach(DEP ${MISSION_DEPS} ${MISSION_PSPMODULES})
set(${DEP}_MISSION_DIR ${${DEP}_MISSION_DIR} PARENT_SCOPE)
endforeach(DEP ${MISSION_DEPS})
# Doxygen-based documentation generation targets
# Create a directory for documentation output
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/doc")
# Generate a customized Doxyfile file for the Doxygen docs.
# This file must be present in the directory where "doxygen" is executed
# If the user has provided a "Doxyfile" in their top level documentation directory,
# then assume they have also set PROJECT_NAME and PROJECT_BRIEF in that.
# Otherwise, generate reasonable strings for these values.
set(MISSION_DOXYFILE_USER_CONTENT)
if (EXISTS "${MISSION_SOURCE_DIR}/doc/Doxyfile")
list(APPEND MISSION_DOXYFILE_USER_CONTENT "@INCLUDE = ${MISSION_SOURCE_DIR}/doc/Doxyfile\n")
endif (EXISTS "${MISSION_SOURCE_DIR}/doc/Doxyfile")
foreach(APP ${MISSION_APPS} ${MISSION_DEPS} ${MISSION_PSPMODULES})
# OSAL is handled specially, as only part of it is used
if (NOT APP STREQUAL "osal" AND NOT APP STREQUAL "cfe-core")
if (EXISTS "${${APP}_MISSION_DIR}/docs/${APP}.doxyfile.in")
# If the module provides its own doxyfile, then include it directly
# This allows for app-specific fine-tuning of the sources, based on its own source tree
configure_file("${${APP}_MISSION_DIR}/docs/${APP}.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/${APP}.doxyfile")
list(APPEND MISSION_DOXYFILE_USER_CONTENT "@INCLUDE = ${CMAKE_BINARY_DIR}/doc/${APP}.doxyfile\n")
else()
# Otherwise just add this entire directory to the "INPUT" list
list(APPEND MISSION_DOXYFILE_USER_CONTENT "INPUT += ${${APP}_MISSION_DIR}\n")
endif()
endif()
endforeach()
# In all cases it is assumed to include the CFE documentation as well (could be configurable?)
file(WRITE "${CMAKE_BINARY_DIR}/doc/mission-content.doxyfile"
${MISSION_DOXYFILE_USER_CONTENT})
configure_file("${CFE_SOURCE_DIR}/cmake/cfe-common.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/cfe-common.doxyfile")
configure_file("${CFE_SOURCE_DIR}/cmake/osal-common.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/osal-common.doxyfile")
configure_file("${CFE_SOURCE_DIR}/cmake/mission-detaildesign.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/mission-detaildesign.doxyfile")
# Generate an "empty" osconfig.h file for doxygen purposes
# this does not have the actual user-defined values, but will
# have the documentation associated with each macro definition.
configure_file("${osal_MISSION_DIR}/osconfig.h.in"
"${CMAKE_BINARY_DIR}/doc/osconfig-example.h")
# The user guide should include the doxygen from the _public_ API files from CFE + OSAL
file(GLOB MISSION_USERGUIDE_HEADERFILES
"${cfe-core_MISSION_DIR}/src/inc/*.h"
"${osal_MISSION_DIR}/src/os/inc/*.h"
"${CMAKE_BINARY_DIR}/doc/osconfig-example.h"
"${MISSION_SOURCE_DIR}/psp/fsw/inc/*.h")
string(REPLACE ";" " \\\n" MISSION_USERGUIDE_HEADERFILES "${MISSION_USERGUIDE_HEADERFILES}")
# OSAL API GUIDE include PUBLIC API
file(GLOB MISSION_OSAL_HEADERFILES
"${osal_MISSION_DIR}/src/os/inc/*.h"
"${CMAKE_BINARY_DIR}/doc/osconfig-example.h")
string(REPLACE ";" " \\\n" MISSION_OSAL_HEADERFILES "${MISSION_OSAL_HEADERFILES}")
configure_file("${CFE_SOURCE_DIR}/cmake/cfe-usersguide.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/cfe-usersguide.doxyfile")
configure_file("${CFE_SOURCE_DIR}/cmake/osalguide.doxyfile.in"
"${CMAKE_BINARY_DIR}/doc/osalguide.doxyfile")
add_custom_target(mission-doc
doxygen mission-detaildesign.doxyfile
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc")
add_custom_target(cfe-usersguide
doxygen cfe-usersguide.doxyfile
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc")
add_custom_target(osalguide
doxygen osalguide.doxyfile
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc")
# Certain runtime variables need to be "exported" to the subordinate build, such as
# the specific arch settings and the location of all the apps. This is done by creating
# a temporary file within the dir and then the subprocess will read that file and re-create
# variables out of them. The alternative to this is to specify many "-D" parameters to the
# subordinate build but that would not scale well to many vars.
set(VARLIST
"MISSION_NAME"
"SIMULATION"
"MISSION_DEFS"
"MISSION_SOURCE_DIR"
"MISSION_BINARY_DIR"
"MISSIONCONFIG"
"MISSION_APPS"
"MISSION_PSPMODULES"
"MISSION_DEPS"
"ENABLE_UNIT_TESTS"
)
foreach(APP ${MISSION_APPS} ${MISSION_PSPMODULES} ${MISSION_DEPS})
list(APPEND VARLIST "${APP}_MISSION_DIR")
endforeach(APP ${MISSION_APPS})
set(MISSION_VARCACHE)
foreach(VARL ${VARLIST})
# It is important to avoid putting any blank lines in the output,
# This will cause the reader to misinterpret the data
if (NOT "${${VARL}}" STREQUAL "")
set(MISSION_VARCACHE "${MISSION_VARCACHE}${VARL}\n${${VARL}}\n")
endif (NOT "${${VARL}}" STREQUAL "")
endforeach(VARL ${VARLIST})
file(WRITE "${CMAKE_BINARY_DIR}/mission_vars.cache" "${MISSION_VARCACHE}")
# Generate version information for the executable file. This is done by executing a small CMAKE
# at _build_ time (not at prep time since it might change between now and then) that collects
# the info out of the version control system in use (git is currently assumed).
add_custom_target(mission-version
COMMAND
${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR}
-P ${CFE_SOURCE_DIR}/cmake/version.cmake
WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}
)
# Generate the tools for the native (host) arch
add_subdirectory(${MISSION_SOURCE_DIR}/tools tools)
# Add a dependency on the table generator tool as this is required for table builds
# The "elf2cfetbl" target should have been added by the "tools" above
add_dependencies(mission-prebuild elf2cfetbl)
# Build version information should be generated as part of the pre-build process
add_dependencies(mission-prebuild mission-version)
# Install the functional test code into the host directory
if (IS_DIRECTORY ${MISSION_DEFS}/functional-test AND DEFINED FT_INSTALL_SUBDIR)
install(DIRECTORY ${MISSION_DEFS}/functional-test/ DESTINATION ${FT_INSTALL_SUBDIR})
endif()
endfunction(prepare)
##################################################################
#
# FUNCTION: process_arch
#
# Called by the top-level CMakeLists.txt to set up targets for this arch
# This is where the real work is done
#
function(process_arch TARGETSYSTEM)
set(CURRSYS "${SYSID_${TARGETSYSTEM}}")
set(ARCH_BINARY_DIR "${CMAKE_BINARY_DIR}/${CURRSYS}")
file(MAKE_DIRECTORY "${ARCH_BINARY_DIR}")
message(STATUS "Configuring for system arch: ${CURRSYS}")
# Note - A warning is issued if you pass CMAKE_TOOLCHAIN_FILE to an already-configured build area
# so an extra check is added to see if this is an initial run or a re-run by checking for a CMakeCache file.
if (NOT CURRSYS STREQUAL "native" AND NOT EXISTS "${ARCH_BINARY_DIR}/CMakeCache.txt")
# Find the toolchain file - allow a file in the mission defs dir to supercede one in the compile dir
if (EXISTS ${MISSION_DEFS}/toolchain-${CURRSYS}.cmake)
set(TOOLCHAIN_FILE ${MISSION_DEFS}/toolchain-${CURRSYS}.cmake)
elseif(EXISTS ${CFE_SOURCE_DIR}/cmake/toolchain-${CURRSYS}.cmake)
set(TOOLCHAIN_FILE ${CFE_SOURCE_DIR}/cmake/toolchain-${CURRSYS}.cmake)
else()
message(FATAL_ERROR "Unable to find toolchain file for ${CURRSYS}")
endif()
set(SELECTED_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}")
else()
# Do not supply any toolchain file option to the subprocess
set(SELECTED_TOOLCHAIN_FILE)
endif ()
# Execute CMake subprocess to create a binary build tree for the specific CPU architecture
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "Unix Makefiles"
-DTARGETSYSTEM=${TARGETSYSTEM}
-DMISSION_BINARY_DIR=${MISSION_BINARY_DIR}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
${SELECTED_TOOLCHAIN_FILE}
${CFE_SOURCE_DIR}
WORKING_DIRECTORY
"${ARCH_BINARY_DIR}"
RESULT_VARIABLE
RESULT
)
if (NOT RESULT EQUAL 0)
message(FATAL_ERROR "Failed to configure ${CURRSYS}")
endif (NOT RESULT EQUAL 0)
# Hook the "make all", "make clean", and "make install" targets for the subordinate build
# to top-level build targets prefixed by the CPU architecture.
add_custom_target(${CURRSYS}-all
COMMAND
$(MAKE) all
WORKING_DIRECTORY
"${ARCH_BINARY_DIR}"
)
add_custom_target(${CURRSYS}-clean
COMMAND
$(MAKE) clean
WORKING_DIRECTORY
"${ARCH_BINARY_DIR}"
)
add_custom_target(${CURRSYS}-install
COMMAND
$(MAKE) install
WORKING_DIRECTORY
"${ARCH_BINARY_DIR}"
)
# All subordinate builds depend on the generated files being present first
add_dependencies(${CURRSYS}-install mission-prebuild)
add_dependencies(${CURRSYS}-all mission-prebuild)
add_dependencies(mission-all ${CURRSYS}-all)
add_dependencies(mission-clean ${CURRSYS}-clean)
add_dependencies(mission-install ${CURRSYS}-install)
endfunction(process_arch TARGETSYSTEM)