Skip to content

Commit 89516fb

Browse files
SebastianBoeAnas Nashif
authored andcommitted
cmake: Change the zephyr_get_* API to be LANG-aware
When exporting flags to an external build system we need to deal with the fact that we sometimes use generator expressions. Specifically, we use generator expressions that look like this: $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions> This patch replaces the old API with a new one where users can ask for compile options for specific languages, like this: zephyr_get_compile_options_for_lang_as_string(CXX x) The existing API would have either crashed or silently omitted flags when a COMPILE_LANG generator expression was present. Signed-off-by: Sebastian Bøe <sebastian.boe@nordicsemi.no>
1 parent b277d3b commit 89516fb

File tree

3 files changed

+121
-51
lines changed

3 files changed

+121
-51
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ add_custom_target(offsets_h DEPENDS ${OFFSETS_H_PATH})
359359

360360
zephyr_include_directories(${TOOLCHAIN_INCLUDES})
361361

362-
zephyr_get_include_directories(ZEPHYR_INCLUDES)
362+
zephyr_get_include_directories_for_lang(C ZEPHYR_INCLUDES)
363363

364364
add_subdirectory(kernel)
365365

cmake/extensions.cmake

Lines changed: 115 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ endfunction()
117117
# includes, options).
118118
#
119119
# The naming convention follows:
120-
# zephyr_get_${build_information}${format}(x)
120+
# zephyr_get_${build_information}_for_lang${format}(lang x)
121121
# Where
122122
# the argument 'x' is written with the result
123123
# and
@@ -128,67 +128,137 @@ endfunction()
128128
# - compile_options # misc. compiler flags
129129
# and
130130
# ${format} can be
131-
# the empty string '', signifying that it should be returned as a list
132-
# _as_string signifying that it should be returned as a string
131+
# - the empty string '', signifying that it should be returned as a list
132+
# - _as_string signifying that it should be returned as a string
133+
# and
134+
# ${lang} can be one of
135+
# - C
136+
# - CXX
137+
# - ASM
133138
#
134139
# e.g.
135-
# zephyr_get_include_directories(x)
140+
# zephyr_get_include_directories_for_lang(ASM x)
136141
# writes "-Isome_dir;-Isome/other/dir" to x
137142

138-
# Utility macro used by the below macros.
139-
macro(get_property_and_add_prefix result target property prefix)
140-
get_property(target_property TARGET ${target} PROPERTY ${property})
141-
foreach(x ${target_property})
142-
list(APPEND ${result} ${prefix}${x})
143-
endforeach()
144-
endmacro()
143+
function(zephyr_get_include_directories_for_lang_as_string lang i)
144+
zephyr_get_include_directories_for_lang(${lang} list_of_flags)
145145

146-
macro(zephyr_get_include_directories i)
147-
get_property_and_add_prefix(${i} zephyr_interface INTERFACE_INCLUDE_DIRECTORIES -I)
148-
endmacro()
146+
convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
149147

150-
macro(zephyr_get_system_include_directories i)
151-
get_property_and_add_prefix(${i} zephyr_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES -isystem)
152-
endmacro()
148+
set(${i} ${str_of_flags} PARENT_SCOPE)
149+
endfunction()
153150

154-
macro(zephyr_get_compile_definitions i)
155-
get_property_and_add_prefix(${i} zephyr_interface INTERFACE_COMPILE_DEFINITIONS -D)
156-
endmacro()
151+
function(zephyr_get_system_include_directories_for_lang_as_string lang i)
152+
zephyr_get_system_include_directories_for_lang(${lang} list_of_flags)
157153

158-
macro(zephyr_get_compile_options i)
159-
get_property(${i} TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS)
160-
endmacro()
154+
convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
155+
156+
set(${i} ${str_of_flags} PARENT_SCOPE)
157+
endfunction()
161158

162-
macro(zephyr_get_include_directories_as_string i)
163-
zephyr_get_include_directories(${i})
159+
function(zephyr_get_compile_definitions_for_lang_as_string lang i)
160+
zephyr_get_compile_definitions_for_lang(${lang} list_of_flags)
164161

165-
string(REPLACE ";" " " ${i} ${${i}})
166-
string(REPLACE "-I" " -I" ${i} ${${i}})
167-
endmacro()
162+
convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
168163

169-
macro(zephyr_get_system_include_directories_as_string i)
170-
get_property_and_add_prefix(${i} zephyr_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES -isystem)
164+
set(${i} ${str_of_flags} PARENT_SCOPE)
165+
endfunction()
171166

172-
string(REPLACE ";" " " ${i} ${${i}})
173-
string(REPLACE "-isystem" " -isystem" ${i} ${${i}})
174-
endmacro()
167+
function(zephyr_get_compile_options_for_lang_as_string lang i)
168+
zephyr_get_compile_options_for_lang(${lang} list_of_flags)
175169

176-
macro(zephyr_get_compile_definitions_as_string i)
177-
get_property_and_add_prefix(${i} zephyr_interface INTERFACE_COMPILE_DEFINITIONS -D)
170+
convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
178171

179-
string(REPLACE ";" " " ${i} ${${i}})
180-
string(REPLACE "-D" " -D" ${i} ${${i}})
181-
endmacro()
172+
set(${i} ${str_of_flags} PARENT_SCOPE)
173+
endfunction()
174+
175+
function(zephyr_get_include_directories_for_lang lang i)
176+
get_property_and_add_prefix(flags zephyr_interface INTERFACE_INCLUDE_DIRECTORIES -I)
177+
178+
process_flags(${lang} flags output_list)
179+
180+
set(${i} ${output_list} PARENT_SCOPE)
181+
endfunction()
182+
183+
function(zephyr_get_system_include_directories_for_lang lang i)
184+
get_property_and_add_prefix(flags zephyr_interface INTERFACE_SYSTEM_INCLUDE_DIRECTORIES -isystem)
185+
186+
process_flags(${lang} flags output_list)
187+
188+
set(${i} ${output_list} PARENT_SCOPE)
189+
endfunction()
190+
191+
function(zephyr_get_compile_definitions_for_lang lang i)
192+
get_property_and_add_prefix(flags zephyr_interface INTERFACE_COMPILE_DEFINITIONS -D)
193+
194+
process_flags(${lang} flags output_list)
195+
196+
set(${i} ${output_list} PARENT_SCOPE)
197+
endfunction()
198+
199+
function(zephyr_get_compile_options_for_lang lang i)
200+
get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS)
201+
202+
process_flags(${lang} flags output_list)
182203

183-
macro(zephyr_get_compile_options_as_string i)
184-
zephyr_get_compile_options(j)
204+
set(${i} ${output_list} PARENT_SCOPE)
205+
endfunction()
206+
207+
function(process_flags lang input output)
208+
# The flags might contains compile language generator expressions that
209+
# look like this:
210+
# $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
211+
#
212+
# Flags that don't specify a language like this apply to all
213+
# languages.
214+
#
215+
# See COMPILE_LANGUAGE in
216+
# https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html
217+
#
218+
# To deal with this, we apply a regex to extract the flag and also
219+
# to find out if the language matches.
220+
#
221+
# If this doesn't work out we might need to ban the use of
222+
# COMPILE_LANGUAGE and instead partition C, CXX, and ASM into
223+
# different libraries
224+
set(languages C CXX ASM)
225+
226+
set(tmp_list "")
227+
228+
foreach(flag ${${input}})
229+
set(is_compile_lang_generator_expression 0)
230+
foreach(l ${languages})
231+
if(flag MATCHES "<COMPILE_LANGUAGE:${l}>:([^>]+)>")
232+
set(is_compile_lang_generator_expression 1)
233+
if(${l} STREQUAL ${lang})
234+
list(APPEND tmp_list ${CMAKE_MATCH_1})
235+
break()
236+
endif()
237+
endif()
238+
endforeach()
185239

186-
foreach(__opt__ ${j})
187-
if(__opt__ MATCHES "<COMPILE_LANGUAGE:")
188-
# TODO: Support COMPILE_LANGUAGE generator expressions
189-
continue()
240+
if(NOT is_compile_lang_generator_expression)
241+
list(APPEND tmp_list ${flag})
190242
endif()
191-
set(${i} "${${i}} ${__opt__}")
243+
endforeach()
244+
245+
set(${output} ${tmp_list} PARENT_SCOPE)
246+
endfunction()
247+
248+
function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags)
249+
# Convert the list to a string so we can do string replace
250+
# operations on it and replace the ";" list separators with a
251+
# whitespace so the flags are spaced out
252+
string(REPLACE ";" " " locally_scoped_string_of_flags "${${ptr_list_of_flags}}")
253+
254+
# Set the output variable in the parent scope
255+
set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE)
256+
endfunction()
257+
258+
macro(get_property_and_add_prefix result target property prefix)
259+
get_property(target_property TARGET ${target} PROPERTY ${property})
260+
foreach(x ${target_property})
261+
list(APPEND ${result} ${prefix}${x})
192262
endforeach()
193263
endmacro()
194264

samples/application_development/external_lib/CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ target_sources(app PRIVATE src/main.c)
1111
# do not need any build information from zephyr. Or they may be
1212
# incompatible with certain zephyr options and need them to be
1313
# filtered out.
14-
zephyr_get_include_directories_as_string(includes)
15-
zephyr_get_system_include_directories_as_string(system_includes)
16-
zephyr_get_compile_definitions_as_string(definitions)
17-
zephyr_get_compile_options_as_string(options)
14+
zephyr_get_include_directories_for_lang_as_string( C includes)
15+
zephyr_get_system_include_directories_for_lang_as_string(C system_includes)
16+
zephyr_get_compile_definitions_for_lang_as_string( C definitions)
17+
zephyr_get_compile_options_for_lang_as_string( C options)
1818

1919
set(external_project_cflags
20-
${includes}${definitions}${options}${system_includes}
20+
"${includes} ${definitions} ${options} ${system_includes}"
2121
)
2222

2323
include(ExternalProject)

0 commit comments

Comments
 (0)