build system switch to cmake

Remove old build system at the same time

Change-Id: Ifdffe1fcd4cfece05f036d8de6e7cb74aca65f62
This commit is contained in:
Dominique Martinet
2018-06-04 10:39:03 +09:00
parent 4bdd9cf512
commit 2a63c962fc
63 changed files with 945 additions and 8357 deletions

View File

@ -0,0 +1,46 @@
Cross compilation:
------------------
The standard way of cross compiling with cmake is to give cmake a "toolchain
file" that describes the compiler prefix and where it can find libraries for
the target system, we provide an example in cmake/cross-aarch64.cmake.
This obviously requires installing a toolchain and a rootfs with target
libraries to link against.
In addition, mckernel borrows the Kbuild system from linux kernel, which also
makes the assumption that you can run generated executables (Kbuild uses various
scripts around module building and does not make the distinction between build
target and host target); you can get this working by setting up qemu-user on your
machine which the kernel will transparently use through binfmt magic when trying
to execute other arch binaries.
# yum install gcc-aarch64-linux-gnu qemu-user
(dnf brings in --forcearch, we use this to setup the sysroot ; there are other
ways of building one. It is available on el7 in extras.)
# yum install dnf dnf-plugins-core
(install these separately because most scripts cannot be run, and dependency hell means we need them first)
# dnf download --releasever=7 --forcearch=aarch64 filesystem centos-release
# rpm --root /usr/aarch64-linux-gnu/sys-root --ignorearch --nodeps -ivh filesystem-*.rpm
# rpm --root /usr/aarch64-linux-gnu/sys-root --ignorearch --nodeps -ivh centos-release-*.rpm
# rpm --root /usr/aarch64-linux-gnu/sys-root --import /usr/aarch64-linux-gnu/sys-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
# rpm --root /usr/aarch64-linux-gnu/sys-root --import /usr/aarch64-linux-gnu/sys-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7-aarch64
# dnf install --releasever=7 --forcearch=aarch64 --installroot=/usr/aarch64-linux-gnu/sys-root/ --setopt=tsflags=noscripts glibc-devel kernel-devel numactl-devel systemd-devel binutils-devel
(el7 lacks a binfmt for aarch64... fix this)
# echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:' > /etc/binfmt.d/qemu-aarch64-dynamic.conf
# systemctl restart systemd-binfmt
(optional) test your setup
# gcc -xc - <<<'#include <stdio.h>'$'\n''int main() { printf("ok\n"); return 0; }'
# export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/sys-root
# file a.out
a.out: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=5ff445d3353cad2dae0a22550fe4cc572287dd90, not stripped
# ./a.out
ok
finally, build mckernel!
# mkdir build; cd build
# export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/sys-root
# cmake -DCMAKE_INSTALL_PREFIX=/tmp/install-aarch64 -DCMAKE_TOOLCHAIN_FILE=../cmake/cross-aarch64.cmake -DUNAME_R=4.14.0-115.2.2.el7a.aarch64 -DKERNEL_DIR=/usr/aarch64-linux-gnu/sys-root/usr/src/kernels/4.14.0-115.2.2.el7a.aarch64/ -DBUILD_TARGET=smp-arm64 ..
# make -j

10
cmake/cross-aarch64.cmake Normal file
View File

@ -0,0 +1,10 @@
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
SET(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
SET(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu/sys-root)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

100
cmake/modules/Kbuild.cmake Normal file
View File

@ -0,0 +1,100 @@
# Interface to kbuild
#
# Generate Kbuild file as appropriate and call make to the kernel build system
# Original goal was to be simple, but correctness is difficult...
set(UNAME_R ${CMAKE_SYSTEM_VERSION} CACHE STRING "Kernel version to build against")
set(KERNEL_DIR "/lib/modules/${UNAME_R}/build" CACHE STRING "kernel build directory")
set(KBUILD_C_FLAGS "" CACHE STRING "Compiler flags to give to Kbuild.")
set(KBUILD_MAKE_FLAGS "" CACHE STRING "Extra make arguments for Kbuild.")
mark_as_advanced(
KBUILD_C_FLAGS
KBUILD_MAKE_FLAGS
)
function(kmod MODULE_NAME)
cmake_parse_arguments(KMOD "" "INSTALL_DEST" "C_FLAGS;SOURCES;EXTRA_SYMBOLS;DEPENDS" ${ARGN})
add_custom_target(${MODULE_NAME}_ko ALL
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.ko"
"${CMAKE_CURRENT_BINARY_DIR}/Module.symvers")
string(REGEX REPLACE "\\.c(;|$)" ".o\\1" KMOD_OBJECTS "${KMOD_SOURCES}")
string(REPLACE ";" " " OBJECTS "${KMOD_OBJECTS}")
string(REPLACE ";" " " C_FLAGS "${KMOD_C_FLAGS}")
string(REPLACE ";" " " EXTRA_SYMBOLS "${KMOD_EXTRA_SYMBOLS}")
if(ENABLE_WERROR)
set(ccflags "${KBUILD_C_FLAGS} ${C_FLAGS} -Werror")
else(ENABLE_WERROR)
set(ccflags "${KBUILD_C_FLAGS} ${C_FLAGS}")
endif(ENABLE_WERROR)
configure_file(${CMAKE_SOURCE_DIR}/cmake/modules/Kbuild.in
${CMAKE_CURRENT_BINARY_DIR}/Kbuild)
if (${CMAKE_GENERATOR} STREQUAL Ninja)
set(MAKE "make")
list(APPEND KBUILD_MAKE_FLAGS "-j")
else ()
set(MAKE "$(MAKE)")
endif ()
if (NOT "${ARCH}" STREQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}")
string(REGEX REPLACE "ld$" "" CROSS_COMPILE "${CMAKE_LINKER}")
list(APPEND KBUILD_MAKE_FLAGS "ARCH=${ARCH};CROSS_COMPILE=${CROSS_COMPILE}")
endif()
string(REGEX REPLACE "\\.c(;|$)" ".o.cmd\\1" KMOD_O_CMD "${KMOD_SOURCES}")
string(REGEX REPLACE "[^/;]+(;|$)" ".\\0" KMOD_O_CMD "${KMOD_O_CMD}")
# This custom command has two uses:
# - first is to list kbuild output files, so make clean does something
# (cmake does not let us add a custom command to make clean)
# - this alone could have been added to the other command, but cmake insists
# on messing with timestamps with touch_nocreate after the command runs,
# so it would incorrectly make intermediary outputs newer than the .ko
# and force kbuild to relink needlessly
add_custom_command(
OUTPUT
old_timestamp
${KMOD_OBJECTS}
${KMOD_O_CMD}
"${MODULE_NAME}.o"
".${MODULE_NAME}.o.cmd"
"${MODULE_NAME}.mod.c"
"${MODULE_NAME}.mod.o"
".${MODULE_NAME}.mod.o.cmd"
".${MODULE_NAME}.ko.cmd"
".tmp_versions/${MODULE_NAME}.mod"
".tmp_versions"
"modules.order"
COMMAND touch old_timestamp
)
# This custom command forces cmake to rebuild the module, so kbuild's dependencies
# (including header files modifications) kick in everytime.
# Ideally, should later be replaced by something parsing the .xxx.cmd files to have
# the native build system do these checks, if possible at all...
add_custom_command(OUTPUT kmod_always_rebuild COMMAND touch kmod_always_rebuild)
add_custom_command(
OUTPUT "${MODULE_NAME}.ko"
"Module.symvers"
COMMAND ${MAKE} ${KBUILD_MAKE_FLAGS} -C ${KERNEL_DIR}
M=${CMAKE_CURRENT_BINARY_DIR} modules
COMMAND rm -f kmod_always_rebuild
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/Kbuild"
${KMOD_DEPENDS}
kmod_always_rebuild
old_timestamp
COMMENT "Building kmod ${MODULE_NAME}"
)
if (KMOD_INSTALL_DEST)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.ko"
DESTINATION "${KMOD_INSTALL_DEST}")
endif (KMOD_INSTALL_DEST)
message("Defined module ${MODULE_NAME}")
endfunction(kmod)

7
cmake/modules/Kbuild.in Normal file
View File

@ -0,0 +1,7 @@
ccflags-y := @ccflags@
src := @CMAKE_CURRENT_SOURCE_DIR@
KBUILD_EXTRA_SYMBOLS := @EXTRA_SYMBOLS@
obj-m := @MODULE_NAME@.o
@MODULE_NAME@-y := @OBJECTS@

43
cmake/modules/Ksym.cmake Normal file
View File

@ -0,0 +1,43 @@
# Lookup symbol addresses from Ksymbol file
set(SYSTEM_MAP "${KERNEL_DIR}/System.map" CACHE STRING "System map to look for symbols")
set(VMLINUX "${KERNEL_DIR}/vmlinux" CACHE STRING "kernel object file")
function(ksym SYMBOL)
cmake_parse_arguments(KSYM "" "PREFIX;SOURCE_FILE;SUFFIX" "" ${ARGN})
execute_process(COMMAND awk "/ ${SYMBOL}$/ { print $1 }" ${SYSTEM_MAP}
OUTPUT_VARIABLE ADDRESS_CANDIDATES OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT ADDRESS_CANDIDATES)
return()
endif()
# listify and get first element
string(REPLACE "\n" ";" ADDRESS_CANDIDATES "${ADDRESS_CANDIDATES}")
list(GET ADDRESS_CANDIDATES 0 ADDRESS)
if (SOURCE_FILE)
foreach(ADDRESS IN LISTS ADDRESS_CANDIDATES)
execute_process(COMMAND addr2line -e ${VMLINUX} ${ADDRESS}
OUTPUT_VARIABLE LINE OUTPUT_STRIP_TRAILING_WHITESPACE)
if(LINE MATCHES ".*${SOURCE_FILE}:.*")
set(FOUND ADDRESS)
break()
endif()
endforeach(ADDRESS)
if(NOT FOUND)
return()
endif()
# ?! why only if source_file?...
execute_process(COMMAND "awk '/ __ksymtab_${SYMBOL}$/ { print $1 }'"
OUTPUT_VARIABLE SYMBOL_EXPORTED OUTPUT_STRIP_TRAILING_WHITESPACE)
if (SYMBOL_EXPORTED)
set(ADDRESS 0)
endif(SYMBOL_EXPORTED)
endif(SOURCE_FILE)
set(${KSYM_PREFIX}KSYM_${SYMBOL}${KSYM_SUFFIX} "0x${ADDRESS}" CACHE INTERNAL "symbol")
endfunction(ksym)