Skip to content

Commit 9da2250

Browse files
committed
Move CMake code for building multilib and variants to subprojects
This patch restructures the top-level CMake script in order to split building the library variants into a separate CMake project. This better encapsulates the code to build the variants, and untethers it from the toolchain builds so that libraries can be developed and tested without having the rebuild the entire toolchain. Similarly, a new subproject has been created to build a multilib set of library variants, using a selected C library. A simple JSON format has been used to define the flags and variants, which are then built and collected into the appropriate layout.
1 parent 77002e7 commit 9da2250

File tree

72 files changed

+3607
-1641
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+3607
-1641
lines changed

CMakeLists.txt

Lines changed: 86 additions & 1515 deletions
Large diffs are not rendered by default.

arm-multilib/CMakeLists.txt

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#
2+
# Copyright (c) 2024, Arm Limited and affiliates.
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# CMake build for a multilib layout of library variants, with each
19+
# variant in a subdirectory and a multilib.yaml file to map flags to
20+
# a variant.
21+
22+
cmake_minimum_required(VERSION 3.20)
23+
24+
project(arm-multilib)
25+
26+
# Root directory of the repo.
27+
set(TOOLCHAIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
28+
29+
# Cache variables to be set by user
30+
set(MULTILIB_JSON "" CACHE STRING "JSON file to load library definitions from.")
31+
set(ENABLE_VARIANTS "all" CACHE STRING "Semicolon separated list of variants to build, or \"all\". Must match entries in the json.")
32+
set(C_LIBRARY "picolibc" CACHE STRING "Which C library to use.")
33+
set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc newlib llvmlibc)
34+
set(LLVM_BINARY_DIR "" CACHE PATH "Path to LLVM toolchain build or install root.")
35+
36+
# If a compiler launcher such as ccache has been set, it should be
37+
# passed down to each subproject build.
38+
set(compiler_launcher_cmake_args "")
39+
if(CMAKE_C_COMPILER_LAUNCHER)
40+
list(APPEND compiler_launcher_cmake_args "-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}")
41+
endif()
42+
if(CMAKE_CXX_COMPILER_LAUNCHER)
43+
list(APPEND compiler_launcher_cmake_args "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}")
44+
endif()
45+
46+
# Arguments to pass down to the library projects.
47+
foreach(arg
48+
LLVM_BINARY_DIR
49+
FVP_INSTALL_DIR
50+
FVP_CONFIG_DIR
51+
)
52+
if(${arg})
53+
list(APPEND passthrough_dirs "-D${arg}=${${arg}}")
54+
endif()
55+
endforeach()
56+
57+
include(ExternalProject)
58+
include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_llvm.cmake)
59+
list(APPEND passthrough_dirs "-DFETCHCONTENT_SOURCE_DIR_LLVMPROJECT=${FETCHCONTENT_SOURCE_DIR_LLVMPROJECT}")
60+
if(C_LIBRARY STREQUAL picolibc)
61+
include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_picolibc.cmake)
62+
list(APPEND passthrough_dirs "-DFETCHCONTENT_SOURCE_DIR_PICOLIBC=${FETCHCONTENT_SOURCE_DIR_PICOLIBC}")
63+
elseif(C_LIBRARY STREQUAL newlib)
64+
include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_newlib.cmake)
65+
list(APPEND passthrough_dirs "-DFETCHCONTENT_SOURCE_DIR_NEWLIB=${FETCHCONTENT_SOURCE_DIR_NEWLIB}")
66+
endif()
67+
68+
# Create one target to run all the tests.
69+
add_custom_target(check-${C_LIBRARY})
70+
add_custom_target(check-compiler-rt)
71+
add_custom_target(check-cxx)
72+
add_custom_target(check-cxxabi)
73+
add_custom_target(check-unwind)
74+
75+
add_custom_target(check-all)
76+
add_dependencies(
77+
check-all
78+
check-${C_LIBRARY}
79+
check-compiler-rt
80+
check-cxx
81+
check-cxxabi
82+
check-unwind
83+
)
84+
85+
# Read the JSON file to load a multilib configuration.
86+
file(READ ${MULTILIB_JSON} multilib_json_str)
87+
string(JSON multilib_defs GET ${multilib_json_str} "libs")
88+
89+
string(JSON lib_count LENGTH ${multilib_defs})
90+
math(EXPR lib_count_dec "${lib_count} - 1")
91+
92+
foreach(lib_idx RANGE ${lib_count_dec})
93+
string(JSON lib_def GET ${multilib_defs} ${lib_idx})
94+
string(JSON variant GET ${lib_def} "variant")
95+
96+
if (variant IN_LIST ENABLE_VARIANTS OR ENABLE_VARIANTS STREQUAL "all")
97+
string(JSON variant_multilib_flags GET ${lib_def} "flags")
98+
# Placeholder libraries won't have a json, so store the error in
99+
# a variable so a fatal error isn't generated.
100+
string(JSON variant_json ERROR_VARIABLE json_error GET ${lib_def} "json")
101+
102+
if(NOT variant_json STREQUAL "json-NOTFOUND")
103+
# Sort by target triple
104+
if(variant MATCHES "^aarch64")
105+
set(parent_dir_name aarch64-none-elf)
106+
else()
107+
set(parent_dir_name arm-none-eabi)
108+
endif()
109+
set(destination_directory "${CMAKE_CURRENT_BINARY_DIR}/multilib/${parent_dir_name}/${variant}")
110+
install(
111+
DIRECTORY ${destination_directory}
112+
DESTINATION ${parent_dir_name}
113+
)
114+
set(variant_json_file ${CMAKE_CURRENT_BINARY_DIR}/json/variants/${variant_json})
115+
116+
ExternalProject_Add(
117+
runtimes-${variant}
118+
PREFIX ${CMAKE_BINARY_DIR}/lib-builds
119+
SOURCE_DIR ${TOOLCHAIN_SOURCE_DIR}/arm-runtimes
120+
INSTALL_DIR ${destination_directory}
121+
CMAKE_ARGS
122+
${compiler_launcher_cmake_args}
123+
${passthrough_dirs}
124+
-DVARIANT_JSON=${variant_json_file}
125+
-DC_LIBRARY=${C_LIBRARY}
126+
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
127+
STEP_TARGETS build install
128+
USES_TERMINAL_CONFIGURE FALSE
129+
USES_TERMINAL_BUILD TRUE
130+
USES_TERMINAL_TEST TRUE
131+
LIST_SEPARATOR ,
132+
CONFIGURE_HANDLED_BY_BUILD TRUE
133+
TEST_EXCLUDE_FROM_MAIN TRUE
134+
)
135+
136+
# Read info from the variant specific json.
137+
# From the json, check which tests are enabled.
138+
file(READ ${variant_json_file} variant_json_str)
139+
foreach(test_enable_var
140+
ENABLE_LIBC_TESTS
141+
ENABLE_COMPILER_RT_TESTS
142+
ENABLE_LIBCXX_TESTS
143+
)
144+
string(JSON read_${test_enable_var} ERROR_VARIABLE json_error GET ${variant_json_str} "args" ${C_LIBRARY} ${test_enable_var})
145+
if(read_${test_enable_var} STREQUAL "json-NOTFOUND")
146+
string(JSON read_${test_enable_var} ERROR_VARIABLE json_error GET ${variant_json_str} "args" "common" ${test_enable_var})
147+
if(read_${test_enable_var} STREQUAL "json-NOTFOUND")
148+
set(read_${test_enable_var} "OFF")
149+
endif()
150+
endif()
151+
endforeach()
152+
set(check_targets "")
153+
if(read_ENABLE_LIBC_TESTS)
154+
list(APPEND check_targets check-${C_LIBRARY})
155+
endif()
156+
if(read_ENABLE_COMPILER_RT_TESTS)
157+
list(APPEND check_targets check-compiler-rt)
158+
endif()
159+
if(read_ENABLE_LIBCXX_TESTS)
160+
list(APPEND check_targets check-cxx)
161+
list(APPEND check_targets check-cxxabi)
162+
list(APPEND check_targets check-unwind)
163+
endif()
164+
foreach(check_target ${check_targets})
165+
ExternalProject_Add_Step(
166+
runtimes-${variant}
167+
${check_target}
168+
COMMAND "${CMAKE_COMMAND}" --build <BINARY_DIR> --target ${check_target}
169+
USES_TERMINAL TRUE
170+
EXCLUDE_FROM_MAIN TRUE
171+
ALWAYS TRUE
172+
)
173+
ExternalProject_Add_StepTargets(runtimes-${variant} ${check_target})
174+
ExternalProject_Add_StepDependencies(
175+
runtimes-${variant}
176+
${check_target}
177+
runtimes-${variant}-build
178+
)
179+
add_custom_target(${check_target}-${variant})
180+
add_dependencies(${check_target} runtimes-${variant}-${check_target})
181+
add_dependencies(${check_target}-${variant} runtimes-${variant}-${check_target})
182+
endforeach()
183+
184+
# Add the variant to the multilib yaml
185+
string(APPEND multilib_yaml_content "- Dir: ${parent_dir_name}/${variant}\n")
186+
string(APPEND multilib_yaml_content " Flags:\n")
187+
string(REPLACE " " ";" multilib_flags_list ${variant_multilib_flags})
188+
foreach(flag ${multilib_flags_list})
189+
string(APPEND multilib_yaml_content " - ${flag}\n")
190+
endforeach()
191+
string(APPEND multilib_yaml_content " Group: stdlibs\n")
192+
else()
193+
# In place of a json, an error message is expected.
194+
string(JSON variant_error_msg GET ${lib_def} "error")
195+
196+
string(APPEND multilib_yaml_content "- Error: \"${variant_error_msg}\"\n")
197+
string(APPEND multilib_yaml_content " Flags:\n")
198+
string(REPLACE " " ";" multilib_flags_list ${variant_multilib_flags})
199+
foreach(flag ${multilib_flags_list})
200+
string(APPEND multilib_yaml_content " - ${flag}\n")
201+
endforeach()
202+
string(APPEND multilib_yaml_content " Group: stdlibs\n")
203+
endif()
204+
endif()
205+
206+
endforeach()
207+
208+
# Multilib file is generated in two parts.
209+
# 1. Template is filled with multilib flags from json
210+
configure_file(
211+
${CMAKE_CURRENT_SOURCE_DIR}/multilib.yaml.in
212+
${CMAKE_CURRENT_BINARY_DIR}/multilib-without-fpus.yaml
213+
@ONLY
214+
)
215+
216+
# 2. multilib-generate.py maps compiler command line options to flags
217+
add_custom_command(
218+
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/multilib-fpus.yaml
219+
COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/multilib-generate.py"
220+
"--clang=${LLVM_BINARY_DIR}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}"
221+
"--llvm-source=${FETCHCONTENT_SOURCE_DIR_LLVMPROJECT}"
222+
>> ${CMAKE_CURRENT_BINARY_DIR}/multilib-fpus.yaml
223+
)
224+
225+
# Combine the two parts.
226+
add_custom_command(
227+
OUTPUT
228+
${CMAKE_CURRENT_BINARY_DIR}/multilib/multilib.yaml
229+
COMMAND
230+
${CMAKE_COMMAND} -E cat
231+
${CMAKE_CURRENT_BINARY_DIR}/multilib-without-fpus.yaml
232+
${CMAKE_CURRENT_BINARY_DIR}/multilib-fpus.yaml
233+
> ${CMAKE_CURRENT_BINARY_DIR}/multilib/multilib.yaml
234+
DEPENDS
235+
${CMAKE_CURRENT_BINARY_DIR}/multilib-without-fpus.yaml
236+
${CMAKE_CURRENT_BINARY_DIR}/multilib-fpus.yaml
237+
)
238+
239+
add_custom_target(multilib-yaml ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/multilib/multilib.yaml)
240+
install(
241+
FILES ${CMAKE_CURRENT_BINARY_DIR}/multilib/multilib.yaml
242+
DESTINATION .
243+
)

0 commit comments

Comments
 (0)