forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
llext-edk.cmake
197 lines (167 loc) · 8.72 KB
/
llext-edk.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
# Copyright (c) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# This script generates a tarball containing all headers and flags necessary to
# build an llext extension. It does so by copying all headers accessible from
# INTERFACE_INCLUDE_DIRECTORIES and generating a Makefile.cflags file (and a
# cmake.cflags one) with all flags necessary to build the extension.
#
# The tarball can be extracted and used in the extension build system to include
# all necessary headers and flags. File paths are made relative to a few key
# directories (build/zephyr, zephyr base, west top dir and application source
# dir), to avoid leaking any information about the host system.
#
# The following arguments are expected:
# - llext_edk_name: Name of the extension, used to name the tarball and the
# install directory variable for Makefile.
# - INTERFACE_INCLUDE_DIRECTORIES: List of include directories to copy headers
# from. It should simply be the INTERFACE_INCLUDE_DIRECTORIES property of the
# zephyr_interface target.
# - llext_edk_file: Output file name for the tarball.
# - llext_edk_cflags: Flags to be used for source compile commands.
# - ZEPHYR_BASE: Path to the zephyr base directory.
# - WEST_TOPDIR: Path to the west top directory.
# - APPLICATION_SOURCE_DIR: Path to the application source directory.
# - PROJECT_BINARY_DIR: Path to the project binary build directory.
# - CONFIG_LLEXT_EDK_USERSPACE_ONLY: Whether to copy syscall headers from the
# edk directory. This is necessary when building an extension that only
# supports userspace, as the syscall headers are regenerated in the edk
# directory.
cmake_minimum_required(VERSION 3.20.0)
if (CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID)
message(FATAL_ERROR
"The LLEXT EDK is not compatible with CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID.")
endif()
set(llext_edk ${PROJECT_BINARY_DIR}/${llext_edk_name})
set(llext_edk_inc ${llext_edk}/include)
# Usage:
# relative_dir(<dir> <relative_out> <bindir_out>)
#
# Helper function to generate relative paths to a few key directories
# (PROJECT_BINARY_DIR, ZEPHYR_BASE, WEST_TOPDIR and APPLICATION_SOURCE_DIR).
# The generated path is relative to the key directory, and the bindir_out
# output variable is set to TRUE if the path is relative to PROJECT_BINARY_DIR.
#
function(relative_dir dir relative_out bindir_out)
cmake_path(IS_PREFIX PROJECT_BINARY_DIR ${dir} NORMALIZE to_prj_bindir)
cmake_path(IS_PREFIX ZEPHYR_BASE ${dir} NORMALIZE to_zephyr_base)
if("${WEST_TOPDIR}" STREQUAL "")
set(to_west_topdir FALSE)
else()
cmake_path(IS_PREFIX WEST_TOPDIR ${dir} NORMALIZE to_west_topdir)
endif()
cmake_path(IS_PREFIX APPLICATION_SOURCE_DIR ${dir} NORMALIZE to_app_srcdir)
# Overall idea is to place included files in the destination dir based on the source:
# files coming from build/zephyr/generated will end up at
# <install-dir>/include/zephyr/include/generated, files coming from zephyr base at
# <install-dir>/include/zephyr/include, files from west top dir (for instance, hal modules),
# at <install-dir>/include and application ones at <install-dir>/include/<application-dir>.
# Finally, everything else (such as external libs not at any of those places) will end up
# at <install-dir>/include/<full-path-to-external-include>, so we avoid any external lib
# stepping at any other lib toes.
if(to_prj_bindir)
cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${PROJECT_BINARY_DIR} OUTPUT_VARIABLE dir_tmp)
set(dest ${llext_edk_inc}/zephyr/${dir_tmp})
elseif(to_zephyr_base)
cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${ZEPHYR_BASE} OUTPUT_VARIABLE dir_tmp)
set(dest ${llext_edk_inc}/zephyr/${dir_tmp})
elseif(to_west_topdir)
cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${WEST_TOPDIR} OUTPUT_VARIABLE dir_tmp)
set(dest ${llext_edk_inc}/${dir_tmp})
elseif(to_app_srcdir)
cmake_path(GET APPLICATION_SOURCE_DIR FILENAME app_dir)
cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${APPLICATION_SOURCE_DIR} OUTPUT_VARIABLE dir_tmp)
set(dest ${llext_edk_inc}/${app_dir}/${dir_tmp})
else()
set(dest ${llext_edk_inc}/${dir})
endif()
set(${relative_out} ${dest} PARENT_SCOPE)
if(to_prj_bindir)
set(${bindir_out} TRUE PARENT_SCOPE)
else()
set(${bindir_out} FALSE PARENT_SCOPE)
endif()
endfunction()
string(REGEX REPLACE "[^a-zA-Z0-9]" "_" llext_edk_name_sane ${llext_edk_name})
string(TOUPPER ${llext_edk_name_sane} llext_edk_name_sane)
set(install_dir_var "${llext_edk_name_sane}_INSTALL_DIR")
separate_arguments(llext_edk_cflags NATIVE_COMMAND ${llext_edk_cflags})
set(make_relative FALSE)
foreach(flag ${llext_edk_cflags})
if (flag STREQUAL "-imacros")
set(make_relative TRUE)
elseif (make_relative)
set(make_relative FALSE)
cmake_path(GET flag PARENT_PATH parent)
cmake_path(GET flag FILENAME name)
relative_dir(${parent} dest bindir)
cmake_path(RELATIVE_PATH dest BASE_DIRECTORY ${llext_edk} OUTPUT_VARIABLE dest_rel)
if(bindir)
list(APPEND imacros_gen_make "-imacros\$(${install_dir_var})/${dest_rel}/${name}")
list(APPEND imacros_gen_cmake "-imacros\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}/${name}")
else()
list(APPEND imacros_make "-imacros\$(${install_dir_var})/${dest_rel}/${name}")
list(APPEND imacros_cmake "-imacros\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}/${name}")
endif()
else()
list(APPEND new_cflags ${flag})
endif()
endforeach()
set(llext_edk_cflags ${new_cflags})
list(APPEND base_flags_make ${llext_edk_cflags} ${imacros_make})
list(APPEND base_flags_cmake ${llext_edk_cflags} ${imacros_cmake})
separate_arguments(include_dirs NATIVE_COMMAND ${INTERFACE_INCLUDE_DIRECTORIES})
file(MAKE_DIRECTORY ${llext_edk_inc})
foreach(dir ${include_dirs})
if (NOT EXISTS ${dir})
continue()
endif()
relative_dir(${dir} dest bindir)
# Use destination parent, as the last part of the source directory is copied as well
cmake_path(GET dest PARENT_PATH dest_p)
file(MAKE_DIRECTORY ${dest_p})
file(COPY ${dir} DESTINATION ${dest_p} FILES_MATCHING PATTERN "*.h")
cmake_path(RELATIVE_PATH dest BASE_DIRECTORY ${llext_edk} OUTPUT_VARIABLE dest_rel)
if(bindir)
list(APPEND inc_gen_flags_make "-I\$(${install_dir_var})/${dest_rel}")
list(APPEND inc_gen_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}")
else()
list(APPEND inc_flags_make "-I\$(${install_dir_var})/${dest_rel}")
list(APPEND inc_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}")
endif()
list(APPEND all_inc_flags_make "-I\$(${install_dir_var})/${dest_rel}")
list(APPEND all_inc_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}")
endforeach()
if(CONFIG_LLEXT_EDK_USERSPACE_ONLY)
# Copy syscall headers from edk directory, as they were regenerated there.
file(COPY ${PROJECT_BINARY_DIR}/edk/include/generated/ DESTINATION ${llext_edk_inc}/zephyr/include/generated)
endif()
# Generate flags for Makefile
list(APPEND all_flags_make ${base_flags_make} ${imacros_gen_make} ${all_inc_flags_make})
list(JOIN all_flags_make " " all_flags_str)
file(WRITE ${llext_edk}/Makefile.cflags "LLEXT_CFLAGS = ${all_flags_str}")
list(JOIN all_inc_flags_make " " all_inc_flags_str)
file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_ALL_INCLUDE_CFLAGS = ${all_inc_flags_str}")
list(JOIN inc_flags_make " " inc_flags_str)
file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_INCLUDE_CFLAGS = ${inc_flags_str}")
list(JOIN inc_gen_flags_make " " inc_gen_flags_str)
file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_GENERATED_INCLUDE_CFLAGS = ${inc_gen_flags_str}")
list(JOIN base_flags_make " " base_flags_str)
file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_BASE_CFLAGS = ${base_flags_str}")
list(JOIN imacros_gen_make " " imacros_gen_str)
file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_GENERATED_IMACROS_CFLAGS = ${imacros_gen_str}")
# Generate flags for CMake
list(APPEND all_flags_cmake ${base_flags_cmake} ${imacros_gen_cmake} ${all_inc_flags_cmake})
file(WRITE ${llext_edk}/cmake.cflags "set(LLEXT_CFLAGS ${all_flags_cmake})")
file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_ALL_INCLUDE_CFLAGS ${all_inc_flags_cmake})")
file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_INCLUDE_CFLAGS ${inc_flags_cmake})")
file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_GENERATED_INCLUDE_CFLAGS ${inc_gen_flags_cmake})")
file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_BASE_CFLAGS ${base_flags_cmake})")
file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_GENERATED_IMACROS_CFLAGS ${imacros_gen_cmake})")
# Generate the tarball
file(ARCHIVE_CREATE
OUTPUT ${llext_edk_file}
PATHS ${llext_edk}
FORMAT gnutar
COMPRESSION XZ
)
file(REMOVE_RECURSE ${llext_edk})