From 277a59f1cba75fa763e5838b3443f11686dd5ebb Mon Sep 17 00:00:00 2001 From: marian cingel Date: Fri, 8 Sep 2023 00:29:47 +0200 Subject: [PATCH] Support Clang/LLVM build on FBSD - Update CMakeList to support installation to PREFIX directory - FreeBSD does not support abstract sockets (unix-abstract:laminar), so explicit 'LAMINAR_BIND_RPC=IP:port' is required - ld.lld requires explicit emulation for binary blobs, add a new variable LINKER_EMULATION_FLAGS for this purpose --- CMakeLists.txt | 79 +++++++++++++++++++++++++++++++++++++++++++------- src/leader.cpp | 8 +++++ src/run.cpp | 19 ++++++++++++ src/server.cpp | 3 +- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7bfe4e..594b71b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,43 @@ cmake_minimum_required(VERSION 3.6) project(laminar) +if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + # ld.lld is a default option on FreeBSD + set(LLVM_LINKER_IS_LLD ON) +endif() + +# ld.lld specific options. There is no sane way in cmake +# to detect if toolchain is actually using ld.lld +if (LLVM_LINKER_IS_LLD) + if (NOT DEFINED LINKER_EMULATION_FLAGS) + if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64") + set(LINKER_EMULATION_FLAGS "-melf_x86_64") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") + set(LINKER_EMULATION_FLAGS "-melf_x86_64") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + set(LINKER_EMULATION_FLAGS "-maarch64elf") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc64le") + set(LINKER_EMULATION_FLAGS "-melf64lppc") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc64") + set(LINKER_EMULATION_FLAGS "-melf64ppc") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64") + # llvm17 & riscv64 requires extra step, it is necessary to + # patch 'Elf64.e_flags' (48-th byte) in binary-blob object files + # with value 0x5 - to change soft_float ABI to hard_float ABI + # so they can link with rest of the object files. + set(LINKER_EMULATION_FLAGS "-melf64lriscv") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm") + set(LINKER_EMULATION_FLAGS "-marmelf") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7") + set(LINKER_EMULATION_FLAGS "-marmelf") + else() + message(FATAL_ERROR + "Unsupported '${CMAKE_SYSTEM_PROCESSOR}' translation to emulation flag. " + "Please set it explicitly 'cmake -DLINKER_EMULATION_FLAGS=\"-melf_your_arch\" ...'") + endif() + endif() +endif() + set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 17) @@ -56,7 +93,7 @@ macro(generate_compressed_bins BASEDIR) DEPENDS ${BASEDIR}/${FILE} ) add_custom_command(OUTPUT ${OUTPUT_FILE} - COMMAND ${CMAKE_LINKER} -r -b binary -o ${OUTPUT_FILE} ${COMPRESSED_FILE} + COMMAND ${CMAKE_LINKER} ${LINKER_EMULATION_FLAGS} -r -b binary -o ${OUTPUT_FILE} ${COMPRESSED_FILE} COMMAND ${CMAKE_OBJCOPY} --rename-section .data=.rodata.alloc,load,readonly,data,contents --add-section .note.GNU-stack=/dev/null @@ -84,11 +121,11 @@ add_custom_command(OUTPUT index_html_size.h # Download 3rd-party frontend JS libs... file(DOWNLOAD https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js - js/vue.min.js EXPECTED_MD5 fb192338844efe86ec759a40152fcb8e) + ${CMAKE_BINARY_DIR}/js/vue.min.js EXPECTED_MD5 fb192338844efe86ec759a40152fcb8e) file(DOWNLOAD https://raw.githubusercontent.com/drudru/ansi_up/v4.0.4/ansi_up.js - js/ansi_up.js EXPECTED_MD5 b31968e1a8fed0fa82305e978161f7f5) + ${CMAKE_BINARY_DIR}/js/ansi_up.js EXPECTED_MD5 b31968e1a8fed0fa82305e978161f7f5) file(DOWNLOAD https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js - js/Chart.min.js EXPECTED_MD5 7dd5ea7d2cf22a1c42b43c40093d2669) + ${CMAKE_BINARY_DIR}/js/Chart.min.js EXPECTED_MD5 7dd5ea7d2cf22a1c42b43c40093d2669) # ...and compile them generate_compressed_bins(${CMAKE_BINARY_DIR} js/vue.min.js js/ansi_up.js js/Chart.min.js) @@ -109,13 +146,31 @@ set(LAMINARD_CORE_SOURCES index_html_size.h ) +find_package(CapnProto REQUIRED) +include_directories(${CAPNP_INCLUDE_DIRS}) + +find_package(SQLite3 REQUIRED) +include_directories(${SQLite3_INCLUDE_DIRS}) + +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIRS}) + +find_package(Threads REQUIRED) +include_directories(${Threads_INCLUDE_DIRS}) + ## Server add_executable(laminard ${LAMINARD_CORE_SOURCES} src/main.cpp ${COMPRESSED_BINS}) -target_link_libraries(laminard capnp-rpc capnp kj-http kj-async kj pthread sqlite3 z) +target_link_libraries(laminard CapnProto::capnp-rpc CapnProto::capnp CapnProto::kj-http CapnProto::kj-async + CapnProto::kj Threads::Threads SQLite::SQLite3 ZLIB::ZLIB) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") +pkg_check_modules(INOTIFY REQUIRED libinotify) +target_link_libraries(laminard ${INOTIFY_LINK_LIBRARIES}) +endif() ## Client add_executable(laminarc src/client.cpp src/version.cpp laminar.capnp.c++) -target_link_libraries(laminarc capnp-rpc capnp kj-async kj pthread) +target_link_libraries(laminarc CapnProto::capnp-rpc CapnProto::capnp CapnProto::kj-async CapnProto::kj Threads::Threads) ## Manpages macro(gzip SOURCE) @@ -144,9 +199,11 @@ set(BASH_COMPLETIONS_DIR /usr/share/bash-completion/completions CACHE PATH "Path set(ZSH_COMPLETIONS_DIR /usr/share/zsh/site-functions CACHE PATH "Path to zsh completions directory") install(TARGETS laminard RUNTIME DESTINATION sbin) install(TARGETS laminarc RUNTIME DESTINATION bin) -install(FILES etc/laminar.conf DESTINATION /etc) -install(FILES etc/laminarc-completion.bash DESTINATION ${BASH_COMPLETIONS_DIR} RENAME laminarc) -install(FILES etc/laminarc-completion.zsh DESTINATION ${ZSH_COMPLETIONS_DIR} RENAME _laminarc) +install(FILES etc/laminarc-completion.bash DESTINATION ${CMAKE_INSTALL_PREFIX}${BASH_COMPLETIONS_DIR} RENAME laminarc) +install(FILES etc/laminarc-completion.zsh DESTINATION ${CMAKE_INSTALL_PREFIX}${ZSH_COMPLETIONS_DIR} RENAME _laminarc) -configure_file(etc/laminar.service.in laminar.service @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/laminar.service DESTINATION ${SYSTEMD_UNITDIR}) +if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + install(FILES etc/laminar.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/etc) + configure_file(etc/laminar.service.in laminar.service @ONLY) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/laminar.service DESTINATION ${CMAKE_INSTALL_PREFIX}${SYSTEMD_UNITDIR}) +endif() \ No newline at end of file diff --git a/src/leader.cpp b/src/leader.cpp index 4d8d82f..fccb7f1 100644 --- a/src/leader.cpp +++ b/src/leader.cpp @@ -21,7 +21,11 @@ #include #include #include +#if defined(__FreeBSD__) +#include +#else #include +#endif #include #include #include @@ -317,7 +321,11 @@ int leader_main(void) { // will be reparented to this one instead of init (or higher layer subreaper). // We do this so that the run will wait until all descedents exit before executing // the next step. + #if defined(__FreeBSD__) + procctl(P_PID, 0, PROC_REAP_ACQUIRE, NULL); + #else prctl(PR_SET_CHILD_SUBREAPER, 1, NULL, NULL, NULL); + #endif // Become the leader of a new process group. This is so that all child processes // will also get a kill signal when the run is aborted diff --git a/src/run.cpp b/src/run.cpp index 3915fe5..0a1feaf 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -21,10 +21,16 @@ #include "conf.h" #include "log.h" +#include #include #include #include +#if defined(__FreeBSD__) +#include +#include +#endif + // short syntax helper for kj::Path template inline kj::Path operator/(const kj::Path& p, const T& ext) { @@ -153,7 +159,20 @@ kj::Promise Run::start(RunState lastResult, std::shared_ptr c // main() by calling leader_main() char* procName; if(asprintf(&procName, "{laminar} %s:%d", name.data(), build) > 0) +#if defined(__FreeBSD__) + { + int sysctl_rq[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + size_t self_exe_len = PATH_MAX; + char self_exe[PATH_MAX]; + + if (sysctl(sysctl_rq, 4, self_exe, &self_exe_len, NULL, 0)) + _exit(EXIT_FAILURE); + + execl(self_exe, procName, NULL); // does not return + } +#else execl("/proc/self/exe", procName, NULL); // does not return +#endif _exit(EXIT_FAILURE); } diff --git a/src/server.cpp b/src/server.cpp index f7aa4c0..06cbbba 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -28,9 +28,8 @@ #include #include -#include -#include #include +#include // Size of buffer used to read from file descriptors. Should be // a multiple of sizeof(struct signalfd_siginfo) == 128