1#
2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7cmake_minimum_required(VERSION 3.8.2)
8include(CheckCCompilerFlag)
9
10include(${CMAKE_CURRENT_LIST_DIR}/configs/seL4Config.cmake)
11project(seL4 C ASM)
12
13# First find our helpers
14find_file(KERNEL_HELPERS_PATH helpers.cmake PATHS tools CMAKE_FIND_ROOT_PATH_BOTH)
15mark_as_advanced(FORCE KERNEL_HELPERS_PATH)
16include(${KERNEL_HELPERS_PATH})
17
18function(RequireTool config file)
19    RequireFile("${config}" "${file}" PATHS tools)
20endfunction(RequireTool)
21
22RequireTool(KERNEL_FLAGS_PATH flags.cmake)
23
24if(CCACHEFOUND)
25    set(ccache "ccache")
26endif()
27
28include(tools/internal.cmake)
29
30# Define tools used by the kernel
31set(PYTHON3 "python3" CACHE INTERNAL "")
32RequireTool(CPP_GEN_PATH cpp_gen.sh)
33RequireTool(CIRCULAR_INCLUDES circular_includes.py)
34RequireTool(BF_GEN_PATH bitfield_gen.py)
35RequireTool(HARDWARE_GEN_PATH hardware_gen.py)
36RequireTool(INVOCATION_ID_GEN_PATH invocation_header_gen.py)
37RequireTool(SYSCALL_ID_GEN_PATH syscall_header_gen.py)
38RequireTool(XMLLINT_PATH xmllint.sh)
39
40# Process the configuration scripts
41include(config.cmake)
42
43# Define default global flag information so that users can compile with the same basic architecture
44# flags as the kernel
45if(KernelArchX86)
46    if(${KernelX86MicroArch} STREQUAL generic)
47        set(build_arch "-mtune=generic")
48    else()
49        set(build_arch "-march=${KernelX86MicroArch}")
50    endif()
51    if(Kernel64)
52        if(NOT LLVM_TOOLCHAIN)
53            string(APPEND asm_common_flags " -Wa,--64")
54        endif()
55        string(APPEND c_common_flags " -m64")
56    else()
57        if(NOT LLVM_TOOLCHAIN)
58            string(APPEND asm_common_flags " -Wa,--32")
59        else()
60            string(APPEND asm_common_flags " -m32")
61        endif()
62        string(APPEND c_common_flags " -m32")
63    endif()
64endif()
65if(KernelArchARM)
66    set(arm_march "${KernelArmArmV}${KernelArmMachFeatureModifiers}")
67    string(APPEND c_common_flags " -march=${arm_march}")
68    string(APPEND asm_common_flags " -march=${arm_march}")
69    # Explicitly request ARM instead of THUMB for compilation. This option is not
70    # relevant on aarch64
71    if(NOT KernelSel4ArchAarch64)
72        string(APPEND c_common_flags " -marm")
73    endif()
74endif()
75if(KernelArchRiscV)
76    if(Kernel64)
77        if(KernelHaveFPU)
78            string(APPEND common_flags " -march=rv64imafdc")
79            string(APPEND common_flags " -mabi=lp64d")
80        else()
81            string(APPEND common_flags " -march=rv64imac")
82            string(APPEND common_flags " -mabi=lp64")
83        endif()
84    else()
85        string(APPEND common_flags " -march=rv32imac")
86        string(APPEND common_flags " -mabi=ilp32")
87    endif()
88endif()
89string(APPEND common_flags " ${build_arch}")
90if(Kernel64)
91    string(APPEND common_flags " -D__KERNEL_64__")
92else()
93    string(APPEND common_flags " -D__KERNEL_32__")
94endif()
95
96set(
97    BASE_ASM_FLAGS "${asm_common_flags} ${common_flags}"
98    CACHE INTERNAL "Default ASM flags for compilation \
99    (subset of flags used by the kernel build)"
100)
101set(
102    BASE_C_FLAGS "${c_common_flags} ${common_flags}"
103    CACHE INTERNAL "Default C flags for compilation \
104    (subset of flags used by the kernel)"
105)
106set(
107    BASE_CXX_FLAGS "${cxx_common_flags} ${c_common_flags} ${common_flags}"
108    CACHE INTERNAL "Default CXX flags for compilation"
109)
110if(KernelArchX86)
111    if(Kernel64)
112        string(APPEND common_exe_flags " -Wl,-m -Wl,elf_x86_64")
113    else()
114        string(APPEND common_exe_flags " -Wl,-m -Wl,elf_i386")
115    endif()
116endif()
117set(
118    BASE_EXE_LINKER_FLAGS "${common_flags} ${common_exe_flags} "
119    CACHE INTERNAL "Default flags for linker an elf binary application"
120)
121# Initializing the kernel build flags starting from the same base flags that the users will use
122include(${KERNEL_FLAGS_PATH})
123
124# Setup kernel specific flags
125macro(KernelCommonFlags)
126    foreach(common_flag IN ITEMS ${ARGV})
127        add_compile_options(${common_flag})
128        string(APPEND CMAKE_EXE_LINKER_FLAGS " ${common_flag} ")
129    endforeach()
130endmacro(KernelCommonFlags)
131KernelCommonFlags(-nostdinc -nostdlib ${KernelOptimisation} -DHAVE_AUTOCONF)
132if(KernelFWholeProgram)
133    KernelCommonFlags(-fwhole-program)
134endif()
135if(KernelDebugBuild)
136    KernelCommonFlags(-DDEBUG -g -ggdb)
137    # Pretend to CMake that we're a release build with debug info. This is because
138    # we do actually allow CMake to do the final link step, so we'd like it not to
139    # strip our binary
140    set(CMAKE_BUILD_TYPE "RelWithDebInfo")
141else()
142    set(CMAKE_BUILD_TYPE "Release")
143endif()
144if(KernelArchX86 AND Kernel64)
145    KernelCommonFlags(-mcmodel=kernel)
146endif()
147if(KernelArchARM)
148    if(KernelSel4ArchAarch64)
149        KernelCommonFlags(-mgeneral-regs-only)
150        if(
151            (CMAKE_C_COMPILER_ID STREQUAL "GNU")
152            AND (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "10.0.0")
153        )
154            add_compile_options(-mno-outline-atomics)
155        endif()
156    else()
157        KernelCommonFlags(-mfloat-abi=soft)
158    endif()
159endif()
160if(KernelArchRiscV)
161    KernelCommonFlags(-mcmodel=medany)
162endif()
163KernelCommonFlags(-fno-pic -fno-pie)
164add_compile_options(
165    -fno-stack-protector
166    -fno-asynchronous-unwind-tables
167    -std=c99
168    -Wall
169    -Werror
170    -Wstrict-prototypes
171    -Wmissing-prototypes
172    -Wnested-externs
173    -Wmissing-declarations
174    -Wundef
175    -Wpointer-arith
176    -Wno-nonnull
177    -ffreestanding
178    # GCC < 10 and clang < 11 put uninitialized global variables into a 'COMMON'
179    # section unless '-fno-common' is specified. The linker will put anything
180    # from 'COMMON' as the end of the '.bss' it nothing else is specified in the
181    # linker script. Besides making the variable placement look odd, this also
182    # tends to waste a page because we puts large aligned block at the end.
183    # Eventually, GCC 10 and clang 11 made '-fno-common' the default, see
184    # - https://gcc.gnu.org/gcc-10/changes.html
185    # - https://releases.llvm.org/11.0.0/tools/clang/docs/ReleaseNotes.html
186    -fno-common
187)
188
189# Add all the common flags to the linker args
190string(APPEND CMAKE_EXE_LINKER_FLAGS " -ffreestanding -Wl,--build-id=none -static -Wl,-n ")
191
192if(KernelArchX86)
193    add_compile_options(-mno-mmx -mno-sse -mno-sse2 -mno-3dnow)
194endif()
195
196# Sort the C sources to ensure a stable layout of the final C file
197list(SORT c_sources)
198# Add the domain schedule now that its sorted
199list(APPEND c_sources "${KernelDomainSchedule}")
200
201# Add static header includes
202include_directories(
203    "include"
204    "include/${KernelWordSize}"
205    "include/arch/${KernelArch}"
206    "include/arch/${KernelArch}/arch/${KernelWordSize}"
207    "include/plat/${KernelPlatform}"
208    "include/plat/${KernelPlatform}/plat/${KernelWordSize}"
209)
210
211if(KernelArchARM)
212    include_directories(
213        "include/arch/arm/armv/${KernelArmArmV}"
214        "include/arch/arm/armv/${KernelArmArmV}/${KernelWordSize}"
215    )
216endif()
217
218if(KernelArmMach STREQUAL "exynos")
219    include_directories("include/plat/exynos_common/")
220endif()
221
222# Add libsel4 include directories. These are explicitly added instead of calling
223# target_link_libraries(${target} sel4) because we don't want to inherit any
224# other build options from libsel4.
225include_directories(
226    "libsel4/include"
227    "libsel4/arch_include/${KernelArch}"
228    "libsel4/sel4_arch_include/${KernelSel4Arch}"
229    "libsel4/sel4_plat_include/${KernelPlatform}"
230    "libsel4/mode_include/${KernelWordSize}"
231)
232
233#
234# Config generation
235#
236
237include_directories($<TARGET_PROPERTY:kernel_Config,INTERFACE_INCLUDE_DIRECTORIES>)
238# The kernel expects to be able to include an 'autoconf.h' file at the moment.
239# So lets generate one for it to use
240# TODO: use the kernel_Config directly
241generate_autoconf(kernel_autoconf "kernel")
242include_directories($<TARGET_PROPERTY:kernel_autoconf,INTERFACE_INCLUDE_DIRECTORIES>)
243
244# Target for the config / autoconf headers. This is what all the other generated headers
245# can depend upon
246add_custom_target(
247    kernel_config_headers
248    DEPENDS
249        kernel_autoconf_Gen
250        kernel_autoconf
251        kernel_Config
252        kernel_Gen
253)
254
255# Target for all generated headers. We start with just all the config / autoconf headers
256add_custom_target(kernel_headers DEPENDS kernel_config_headers)
257
258# Build up a list of generated files. needed for dependencies in custom commands
259get_generated_files(gen_files_list kernel_autoconf_Gen)
260get_generated_files(gen_files2 kernel_Gen)
261list(APPEND gen_files_list "${gen_files2}")
262
263#
264# C source generation
265#
266
267# Kernel compiles all C sources as a single C file, this provides
268# rules for doing the concatenation
269
270add_custom_command(
271    OUTPUT kernel_all.c
272    COMMAND
273        "${CPP_GEN_PATH}" ${c_sources} > kernel_all.c
274    DEPENDS "${CPP_GEN_PATH}" ${c_sources}
275    COMMENT "Concatenating C files"
276    VERBATIM
277)
278
279add_custom_target(kernel_all_c_wrapper DEPENDS kernel_all.c)
280
281#
282# Header Generation
283#
284
285# Rules for generating invocation and syscall headers
286# Aside from generating file rules for dependencies this section will also produce a target
287# that can be depended upon (along with the desired files themselves) to control parallelism
288
289set(xml_headers "")
290set(header_dest "gen_headers/arch/api/invocation.h")
291gen_invocation_header(
292    OUTPUT ${header_dest}
293    XML ${CMAKE_CURRENT_SOURCE_DIR}/libsel4/arch_include/${KernelArch}/interfaces/sel4arch.xml
294    ARCH
295)
296list(APPEND xml_headers "${header_dest}")
297list(APPEND gen_files_list "${header_dest}")
298
299set(header_dest "gen_headers/arch/api/sel4_invocation.h")
300gen_invocation_header(
301    OUTPUT "${header_dest}"
302    XML
303        "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/sel4_arch_include/${KernelSel4Arch}/interfaces/sel4arch.xml"
304    SEL4ARCH
305)
306list(APPEND xml_headers "${header_dest}")
307list(APPEND gen_files_list "${header_dest}")
308
309set(header_dest "gen_headers/api/invocation.h")
310gen_invocation_header(
311    OUTPUT "${header_dest}"
312    XML "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/include/interfaces/sel4.xml"
313)
314list(APPEND xml_headers "${header_dest}")
315list(APPEND gen_files_list "${header_dest}")
316
317set(syscall_xml_base "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/include/api")
318set(syscall_dest "gen_headers/arch/api/syscall.h")
319if(KernelIsMCS)
320    set(mcs --mcs)
321endif()
322add_custom_command(
323    OUTPUT ${syscall_dest}
324    COMMAND
325        "${XMLLINT_PATH}"
326        --noout
327        --schema "${syscall_xml_base}/syscall.xsd" "${syscall_xml_base}/syscall.xml"
328    COMMAND
329        ${CMAKE_COMMAND} -E remove -f "${syscall_dest}"
330    COMMAND
331        ${PYTHON3} "${SYSCALL_ID_GEN_PATH}"
332        --xml "${syscall_xml_base}/syscall.xml"
333        --kernel_header "${syscall_dest}" ${mcs}
334    DEPENDS
335        "${XMLLINT_PATH}"
336        "${SYSCALL_ID_GEN_PATH}"
337        "${syscall_xml_base}/syscall.xsd"
338        "${syscall_xml_base}/syscall.xml"
339    COMMENT "Generate syscall invocations"
340    VERBATIM
341)
342list(APPEND xml_headers "${syscall_dest}")
343list(APPEND gen_files_list "${syscall_dest}")
344# Construct target for just the xml headers
345add_custom_target(xml_headers_target DEPENDS ${xml_headers})
346# Add the xml headers to all the kernel headers
347add_dependencies(kernel_headers xml_headers_target)
348include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen_headers")
349
350#
351# Prune list generation
352#
353
354# When generating bitfield files we can pass multiple '--prune' parameters that are source
355# files that get searched for determing which bitfield functions are used. This allows the
356# bitfield generator to only generate functions that are used. Whilst irrelevant for
357# normal compilation, not generating unused functions has significant time savings for the
358# automated verification tools
359
360# To generate a prune file we 'build' the kernel (similar to the kernel_all_pp.c rule
361# below) but strictly WITHOUT the generated header directory where the bitfield generated
362# headers are. This means our preprocessed file will contain all the code used by the
363# normal compilation, just without the bitfield headers (which we generate dummy versions of).
364# If we allowed the bitfield headers to be included then we would have a circular
365# dependency. As a result this rule comes *before* the Bitfield header generation section
366
367set(dummy_headers "")
368foreach(bf_dec ${bf_declarations})
369    string(
370        REPLACE
371            ":"
372            ";"
373            bf_dec
374            ${bf_dec}
375    )
376    list(GET bf_dec 0 bf_file)
377    list(GET bf_dec 1 bf_gen_dir)
378    get_filename_component(bf_name "${bf_file}" NAME)
379    string(
380        REPLACE
381            ".bf"
382            "_gen.h"
383            bf_target
384            "${bf_name}"
385    )
386    list(
387        APPEND
388            dummy_headers "${CMAKE_CURRENT_BINARY_DIR}/generated_prune/${bf_gen_dir}/${bf_target}"
389    )
390endforeach()
391
392add_custom_command(
393    OUTPUT ${dummy_headers}
394    COMMAND
395        ${CMAKE_COMMAND} -E touch ${dummy_headers}
396    COMMENT "Generate dummy headers for prune compilation"
397)
398
399add_custom_target(dummy_header_wrapper DEPENDS ${dummy_headers})
400
401cppfile(
402    kernel_all_pp_prune.c
403    kernel_all_pp_prune_wrapper
404    kernel_all.c
405    EXTRA_FLAGS
406    -CC
407    "-I${CMAKE_CURRENT_BINARY_DIR}/generated_prune"
408    EXTRA_DEPS
409    kernel_all_c_wrapper
410    dummy_header_wrapper
411    xml_headers_target
412    kernel_config_headers
413    ${gen_files_list}
414)
415
416#
417# Bitfield header generation
418#
419
420# Need to generate a bunch of unique targets, we'll do this with piano numbers
421set(bf_gen_target "kernel_bf_gen_target_1")
422
423foreach(bf_dec ${bf_declarations})
424    string(
425        REPLACE
426            ":"
427            ";"
428            bf_dec
429            ${bf_dec}
430    )
431    list(GET bf_dec 0 bf_file)
432    list(GET bf_dec 1 bf_gen_dir)
433    get_filename_component(bf_name "${bf_file}" NAME)
434    string(
435        REPLACE
436            ".bf"
437            "_gen.h"
438            bf_target
439            "${bf_name}"
440    )
441    string(
442        REPLACE
443            ".bf"
444            "_defs.thy"
445            defs_target
446            "${bf_name}"
447    )
448    string(
449        REPLACE
450            ".bf"
451            "_proofs.thy"
452            proofs_target
453            "${bf_name}"
454    )
455    set(pbf_name "generated/${bf_gen_dir}/${bf_name}.pbf")
456    set(pbf_target "${bf_gen_target}_pbf")
457    cppfile(
458        "${pbf_name}"
459        "${pbf_target}"
460        "${bf_file}"
461        EXTRA_FLAGS
462        -P
463        EXTRA_DEPS
464        kernel_config_headers
465        ${gen_files_list}
466    )
467    GenHBFTarget(
468        ""
469        ${bf_gen_target}
470        "generated/${bf_gen_dir}/${bf_target}"
471        "${pbf_name}"
472        "${pbf_target}"
473        "kernel_all_pp_prune.c"
474        "kernel_all_pp_prune_wrapper"
475    )
476    GenDefsBFTarget(
477        "${bf_gen_target}_def"
478        "generated/${bf_gen_dir}/${defs_target}"
479        "${pbf_name}"
480        "${pbf_target}"
481        "kernel_all_pp_prune.c"
482        "kernel_all_pp_prune_wrapper"
483    )
484    GenProofsBFTarget(
485        "${bf_gen_target}_proof"
486        "generated/${bf_gen_dir}/${proofs_target}"
487        "${pbf_name}"
488        "${pbf_target}"
489        "kernel_all_pp_prune.c"
490        "kernel_all_pp_prune_wrapper"
491    )
492    list(
493        APPEND
494            theories_deps
495            "${bf_gen_target}_def"
496            "${CMAKE_CURRENT_BINARY_DIR}/generated/${bf_gen_dir}/${defs_target}"
497            "${bf_gen_target}_proof"
498            "${CMAKE_CURRENT_BINARY_DIR}/generated/${bf_gen_dir}/${proofs_target}"
499    )
500    add_dependencies(kernel_headers "${bf_gen_target}")
501    list(APPEND gen_files_list "${CMAKE_CURRENT_BINARY_DIR}/generated/${bf_gen_dir}/${bf_target}")
502    set(bf_gen_target "${bf_gen_target}1")
503endforeach()
504# At this point we have generated a bunch of headers into ${CMAKE_CURRENT_BINARY_DIR}/generated
505# but we do not pass this to include_directories, as that will cause it to be an include directory
506# for *all* targets in this file (including ones we defined earlier) and the prune generation
507# *must not* see this files and generate dependencies on them as this will result in nonsense.
508# As such we must manually add this as an include directory to future targets
509set(CPPExtraFlags "-I${CMAKE_CURRENT_BINARY_DIR}/generated")
510
511#
512# Kernel compilation
513#
514
515cppfile(
516    kernel_all.i
517    kernel_i_wrapper
518    kernel_all.c
519    EXTRA_DEPS
520    kernel_all_c_wrapper
521    kernel_headers
522    ${gen_files_list}
523    EXTRA_FLAGS
524    -CC
525    "${CPPExtraFlags}"
526    # The circular_includes script relies upon parsing out exactly 'kernel_all_copy.c' as
527    # a special case so we must ask cppfile to use this input name
528    EXACT_NAME kernel_all_copy.c
529)
530
531# Explain to cmake that our object file is actually a C input file
532set_property(SOURCE kernel_all.i PROPERTY LANGUAGE C)
533
534if(KernelArchARM)
535    set(linker_source "src/arch/arm/common_arm.lds")
536elseif(KernelArchRiscV)
537    set(linker_source "src/arch/riscv/common_riscv.lds")
538else()
539    set(linker_source "src/plat/${KernelPlatform}/linker.lds")
540endif()
541set(linker_lds_path "${CMAKE_CURRENT_BINARY_DIR}/linker.lds_pp")
542
543# Preprocess the linker script
544cppfile(
545    "${linker_lds_path}"
546    linker_ld_wrapper
547    "${linker_source}"
548    EXTRA_DEPS
549    kernel_headers
550    ${gen_files_list}
551    EXTRA_FLAGS
552    -CC
553    -P
554    "${CPPExtraFlags}"
555)
556
557add_custom_command(
558    OUTPUT circular_includes_valid
559    COMMAND ${CIRCULAR_INCLUDES} --ignore kernel_all_copy.c < kernel_all.i
560    COMMAND touch circular_includes_valid
561    DEPENDS kernel_i_wrapper kernel_all.i
562)
563
564add_custom_target(circular_includes DEPENDS circular_includes_valid)
565
566add_custom_command(
567    OUTPUT kernel_all_pp.c
568    COMMAND
569        ${CMAKE_COMMAND} -E copy kernel_all.i kernel_all_pp.c
570    DEPENDS kernel_i_wrapper kernel_all.i
571)
572add_custom_target(kernel_all_pp_wrapper DEPENDS kernel_all_pp.c)
573
574add_custom_target(kernel_theories DEPENDS ${theories_deps})
575
576# Declare final kernel output
577add_executable(kernel.elf EXCLUDE_FROM_ALL ${asm_sources} kernel_all.c)
578target_include_directories(kernel.elf PRIVATE ${config_dir})
579target_include_directories(kernel.elf PRIVATE include)
580target_include_directories(kernel.elf PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/generated")
581target_link_libraries(kernel.elf PRIVATE kernel_Config kernel_autoconf)
582set_property(TARGET kernel.elf APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-T ${linker_lds_path} ")
583set_target_properties(kernel.elf PROPERTIES LINK_DEPENDS "${linker_lds_path}")
584add_dependencies(kernel.elf circular_includes)
585
586# The following commands setup the install target for copying generated files and
587# compilation outputs to an install location: CMAKE_INSTALL_PREFIX.
588# CMAKE_INSTALL_PREFIX can be set on the cmake command line.
589#
590# The current installation outputs are:
591# - ${CMAKE_INSTALL_PREFIX}/bin/kernel.elf: Location of kernel.elf binary
592# - ${CMAKE_INSTALL_PREFIX}/libsel4/include: The include root for libsel4
593# - ${CMAKE_INSTALL_PREFIX}/libsel4/src: The c source files for the libsel4 library
594#
595# The install target is only created if this is the top level project.
596# We don't currently support creating install targets if the kernel is
597# imported in another project.
598if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
599
600    # Import libsel4 to get access to generation targets
601    add_subdirectory(libsel4)
602    # Add a default target that builds kernel.elf and generates all libsel4 headers
603    add_custom_target(single-project ALL DEPENDS sel4_generated kernel.elf)
604    # Disable the libsel4.a target as we don't intend to build the libsel4 sources
605    set_target_properties(sel4 PROPERTIES EXCLUDE_FROM_ALL ON)
606    # Install kernel.elf to bin/kernel.elf
607    install(TARGETS kernel.elf RUNTIME DESTINATION bin)
608    # Install all libsel4 headers to libsel4/include
609    install(
610        DIRECTORY
611            "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/include/"
612            "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/arch_include/${KernelArch}/"
613            "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/sel4_arch_include/${KernelSel4Arch}/"
614            "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/sel4_plat_include/${KernelPlatform}/"
615            "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/mode_include/${KernelWordSize}/"
616            "${CMAKE_CURRENT_BINARY_DIR}/libsel4/include/"
617            "${CMAKE_CURRENT_BINARY_DIR}/libsel4/arch_include/${KernelArch}/"
618            "${CMAKE_CURRENT_BINARY_DIR}/libsel4/sel4_arch_include/${KernelSel4Arch}/"
619            # The following directories install the autoconf headers
620            "${CMAKE_CURRENT_BINARY_DIR}/gen_config/"
621            "${CMAKE_CURRENT_BINARY_DIR}/libsel4/gen_config/"
622            "${CMAKE_CURRENT_BINARY_DIR}/libsel4/autoconf/"
623        DESTINATION libsel4/include
624        FILES_MATCHING
625        PATTERN "*.h"
626    )
627    # Install libsel4 sources to libsel4/src
628    install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libsel4/src/" DESTINATION libsel4/src)
629
630endif()
631