From f07596dbb516329d27ea95060a758f5d48d26366 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 7 Aug 2023 19:39:57 -0700 Subject: [PATCH] Add CMake and tests - Port tests to GitLab - Add GitLab CI test matrix - Remove gtest submodule --- .gitignore | 3 + .gitlab-ci.yml | 67 +++ .gitmodules | 3 - CHANGES.md | 17 + CMakeLists.txt | 97 ++++ CMakePresets.json | 306 +++++++++++ CTestConfig.cmake | 1 + README.md | 44 +- ci/ctest/Sanitizers-ASAN-CTest.cmake | 66 +++ ci/ctest/Sanitizers-UBSAN-CTest.cmake | 69 +++ ci/gitlab/test.gitlab-ci.yml | 155 ++++++ ci/run-with-msvc.cmd | 3 + cmake/FindDkToolScripts.cmake | 88 ++++ dk | 701 ++++++++++++++++++++++++++ dk.cmd | 146 ++++++ environment.yml | 7 + gtest | 1 - tests/CMakeLists.txt | 12 + tests/example-test.cpp | 2 +- 19 files changed, 1760 insertions(+), 28 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 CHANGES.md create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 CTestConfig.cmake create mode 100644 ci/ctest/Sanitizers-ASAN-CTest.cmake create mode 100644 ci/ctest/Sanitizers-UBSAN-CTest.cmake create mode 100644 ci/gitlab/test.gitlab-ci.yml create mode 100644 ci/run-with-msvc.cmd create mode 100644 cmake/FindDkToolScripts.cmake create mode 100755 dk create mode 100755 dk.cmd create mode 100644 environment.yml delete mode 160000 gtest create mode 100644 tests/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 8d57551..0dfb6b2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ c-capnproto.pc subprojects/googletest-* subprojects/packagecache + +/build/ +/.ci/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..2b59c96 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,67 @@ +.conda-c-cmake:before: + # Use: + # docker run -it --platform linux/amd64 continuumio/miniconda3:22.11.1 + # to test out on a local developer machine (including macOS/ARM64 Silicon) + image: continuumio/miniconda3:22.11.1 + variables: + CONDA_PKGS_DIRS: "$CI_PROJECT_DIR/.conda-pkgs-cache" + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + DEBIAN_FRONTEND: noninteractive + + cache: + key: + files: + - environment.yml + prefix: cachebust1 + paths: + - _local + # Technique explained at https://damiankula.com/using_conda_cache_in_gitlabci.html + - $CONDA_PKGS_DIRS/*.conda + - $CONDA_PKGS_DIRS/*.tar.bz2 + - $CONDA_PKGS_DIRS/urls* + - $CONDA_PKGS_DIRS/cache + # yay, we don't use pip: - $PIP_CACHE_DIR + + before_script: + # Update/install system pkgs first, so conda can use latest system pkgs. + - apt-get update + # Install Ninja + rsync. + # ninja: CMake configure + # build-essential: CMake project(LANGUAGES C) + - apt-get install -qq -o=Dpkg::Use-Pty=0 ninja-build build-essential > /dev/null + # Install CMake + - ./dk dksdk.cmake.link + + # Install Python + - conda env create --quiet -f environment.yml + +.c-cmake-debian:before: + image: debian:stable-slim + variables: + DEBIAN_FRONTEND: noninteractive # for apt-get + before_script: + # Update/install system pkgs first, so conda can use latest system pkgs. + - apt-get update + # Install Ninja and C compiler + # ninja: CMake configure + # clang-tidy: CMake -D BUILD_HYGIENE=ENABLED (or the unset default) + # wget: ci/install-cmake.sh + # build-essential: CMake project(LANGUAGES C) + # git: CMake FetchContent() + # valgrind: ctest -T memcheck + - apt-get install -qq -o=Dpkg::Use-Pty=0 ninja-build clang-tidy wget build-essential git valgrind > /dev/null + # Install CMake + - ./dk dksdk.cmake.link + +.c-cmake-windows:before: + tags: [shared-windows, windows, windows-1809] + variables: + VSDIR: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools + DKSDK_NINJA_PROGRAM: "$CI_PROJECT_DIR\\.ci\\ninja\\bin\\ninja.exe" + before_script: + # https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/gcp/windows-containers/blob/main/cookbooks/preinstalled-software/README.md + # CMake is already present on GitLab CI/CD. No 'choco install -y cmake' (choco frequents gets HTTP 403) or './dk dksdk.cmake.link' needed + - ./dk dksdk.ninja.link + +include: + - local: ci/gitlab/test.gitlab-ci.yml diff --git a/.gitmodules b/.gitmodules index 48294b1..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "gtest"] - path = gtest - url = https://github.com/google/googletest.git diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..7807735 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,17 @@ +# Changes + +## 0.9.0 + +- Forked to the DkML repository on GitLab. +- Use binary mode when reading schemas on Windows +- Use SSIZE_T from `BaseTsd.h` to allow MSVC to compile with 32-bits +- Put alignment on segment fields, not just the structure. +- Avoids left shifts of signed integers, which is undefined C behavior. Passes + ASAN (not a false positive) +- Wrap macro parameters in the `capnp_use(x)` macro. Passes clang-tidy (not + a false positive) + + +## 0.3 (632f0d73a1f4a03026b5e4727386b9fe3ec6e00e) + +- Fork of `c-capnproto-0.3` plus several untagged commits from https://github.com/opensourcerouting/c-capnproto on Apr 23, 2023. Specifically: https://github.com/opensourcerouting/c-capnproto/commit/632f0d73a1f4a03026b5e4727386b9fe3ec6e00e diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ecd2f5d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +cmake_minimum_required(VERSION 3.22) +if(BUILD_TESTING) + # The tests are C++ + set(languages C CXX) +else() + set(languages C) +endif() +project(c-capnproto LANGUAGES ${languages}) + +include(CTest) + +# Stop noise if CXX compiler is set. +set(ignoreAndAvoidCMakeUnusedWarning "${CMAKE_CXX_COMPILER}") + +# Boilerplate DK CMAKE PROJ 2023-05-17.1 +if(APPLE) + set(CMAKE_MACOSX_RPATH OFF) +endif() + +# Boilerplate DK CMAKE PROJ 2023-05-17.2 +if(BUILD_SHARED_LIBS) + # SHARED is implied by BUILD_SHARED_LIBS=ON + set(linkage) +else() + set(linkage STATIC) +endif() + +# Build hygiene: Tools for keeping the source code clean. By default +# we try to enforce build hygiene. +# You can override with either BUILD_HYGIENE=DISABLED or +# BUILD_HYGIENE=ENABLED. +if(NOT BUILD_HYGIENE STREQUAL DISABLED) + if(BUILD_HYGIENE STREQUAL ENABLED) + set(find_program_args REQUIRED) + else() + set(find_program_args) + endif() + find_program(CLANG_TIDY_PROGRAM + NAMES clang-tidy + PATHS + # On macOS the easiest way to get clang-tidy is to install the + # keg-only (not installed into PATH) big `llvm` package. + /opt/homebrew/opt/llvm/bin + /usr/local/opt/llvm/bin + ${find_program_args}) +endif() + +add_library(CapnC_Runtime ${linkage} + lib/capn.c + lib/capn-malloc.c + lib/capn-stream.c + lib/capnp_c.h) +add_library(CapnC::Runtime ALIAS CapnC_Runtime) +set_target_properties(CapnC_Runtime PROPERTIES + EXPORT_NAME Runtime + WINDOWS_EXPORT_ALL_SYMBOLS ON) +target_include_directories(CapnC_Runtime + PUBLIC + $ + $ + $) + +add_executable(capnpc-c + compiler/capnpc-c.c + compiler/schema.capnp.c + compiler/str.c) +target_link_libraries(capnpc-c CapnC_Runtime) +target_include_directories(capnpc-c + PRIVATE lib) + +# Boilerplate DK CMAKE PROJ 2023-05-17.3 +if(BUILD_SHARED_LIBS) + if(APPLE) + set(base @loader_path) + else() + set(base $ORIGIN) + endif() + file(RELATIVE_PATH relDir + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) + set(CMAKE_INSTALL_RPATH + # best practice RPATH locations when installed + ${base} + ${base}/${relDir}) +endif() + +install(TARGETS CapnC_Runtime capnpc-c + EXPORT CapnC) +install(EXPORT CapnC + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CapnC + NAMESPACE CapnC:: + FILE CapnCConfig.cmake) +install(FILES lib/capnp_c.h TYPE INCLUDE) + +if(BUILD_TESTING) + add_subdirectory(tests) +endif() diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..cc6d8a4 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,306 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22 + }, + "configurePresets": [ + { + "name": "ci-agnostic-configure", + "binaryDir": "build", + "hidden": true, + "description": "ABI-agnostic CI configuration for build and test presets" + }, + { + "name": "ci-tests-configure", + "inherits": [ + "ci-agnostic-configure" + ], + "cacheVariables": { + "BUILD_TESTING": "ON" + } + }, + { + "name": "ci-clang_gcc-sanitizers-asan", + "description": "Address sanitizer for clang and GCC", + "cacheVariables": { + "BUILD_TESTING": "ON", + "CMAKE_C_FLAGS_INIT": "-fsanitize=address -fno-sanitize-recover=all", + "CMAKE_EXE_LINKER_FLAGS_INIT": "-fsanitize=address -fno-sanitize-recover=all", + "CMAKE_C_FLAGS_INIT_REASONS": "https://developers.redhat.com/blog/2021/05/05/memory-error-checking-in-c-and-c-comparing-sanitizers-and-valgrind. Because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94328 ASAN and UBSAN don't work together with [log_path] which is needed for CTest" + } + }, + { + "name": "ci-clang_gcc-sanitizers-ubsan", + "description": "Undefined behavior sanitizer for clang and GCC", + "cacheVariables": { + "BUILD_TESTING": "ON", + "CMAKE_C_FLAGS_INIT": "-fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment", + "CMAKE_EXE_LINKER_FLAGS_INIT": "-fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment", + "CMAKE_C_FLAGS_INIT_REASONS": "https://developers.redhat.com/blog/2021/05/05/memory-error-checking-in-c-and-c-comparing-sanitizers-and-valgrind. Because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94328 ASAN and UBSAN don't work together with [log_path] which is needed for CTest" + } + }, + { + "name": "ci-host-windows_x86", + "hidden": true, + "cacheVariables": { + "CMAKE_MAKE_PROGRAM": "$env{DKSDK_NINJA_PROGRAM}", + "ENV-DKSDK_NINJA_PROGRAM": "Set the environment variable DKSDK_NINJA_PROGRAM to the path to ninja.exe" + } + }, + { + "name": "ci-target-windows_x86", + "hidden": true, + "generator": "Ninja", + "architecture": { + "value": "x86", + "strategy": "external" + } + }, + { + "name": "ci-host-windows_x86_64", + "hidden": true, + "cacheVariables": { + "CMAKE_MAKE_PROGRAM": "$env{DKSDK_NINJA_PROGRAM}", + "ENV-DKSDK_NINJA_PROGRAM": "Set the environment variable DKSDK_NINJA_PROGRAM to the path to ninja.exe" + } + }, + { + "name": "ci-target-windows_x86_64", + "hidden": true, + "generator": "Ninja", + "architecture": { + "value": "x64", + "strategy": "external" + } + }, + { + "name": "ci-host-linux_x86", + "hidden": true + }, + { + "name": "ci-target-linux_x86", + "hidden": true + }, + { + "name": "ci-host-linux_x86_64", + "hidden": true + }, + { + "name": "ci-target-linux_x86_64", + "hidden": true + }, + { + "name": "ci-host-darwin_arm64", + "hidden": true, + "cacheVariables": { + "CMAKE_APPLE_SILICON_PROCESSOR": "arm64" + } + }, + { + "name": "ci-target-darwin_arm64", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64", + "CMAKE_EXE_LINKER_FLAGS": "-arch arm64", + "CMAKE_MODULE_LINKER_FLAGS": "-arch arm64", + "CMAKE_SHARED_LINKER_FLAGS": "-arch arm64", + "CMAKE_C_COMPILER": "/usr/bin/clang", + "CMAKE_CXX_COMPILER": "/usr/bin/clang++" + }, + "environment": { + "CMAKE_x_LINKER_FLAGS_REASON": "DkSDK OCaml uses a single target architecture", + "CMAKE_x_COMPILER_REASON": "Direct use of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc (14.0.0) will fail to link with -lm, -lSystem, etc." + } + }, + { + "name": "ci-host-darwin_x86_64", + "hidden": true, + "cacheVariables": { + "CMAKE_APPLE_SILICON_PROCESSOR": "x86_64" + } + }, + { + "name": "ci-target-darwin_x86_64", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "x86_64", + "CMAKE_EXE_LINKER_FLAGS": "-arch x86_64", + "CMAKE_MODULE_LINKER_FLAGS": "-arch x86_64", + "CMAKE_SHARED_LINKER_FLAGS": "-arch x86_64", + "CMAKE_C_COMPILER": "/usr/bin/clang", + "CMAKE_CXX_COMPILER": "/usr/bin/clang++" + }, + "environment": { + "CMAKE_x_LINKER_FLAGS_REASON": "DkSDK OCaml uses a single target architecture", + "CMAKE_x_COMPILER_REASON": "Direct use of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc (14.0.0) will fail to link with -lm, -lSystem, etc." + } + }, + { + "name": "ci-darwin_x86_64", + "inherits": [ + "ci-tests-configure", + "ci-host-darwin_x86_64", + "ci-target-darwin_x86_64" + ], + "displayName": "darwin_x86_64", + "description": "Test builds for darwin_x86_64", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_64", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86_64", + "ci-target-linux_x86_64" + ], + "displayName": "linux_x86_64", + "description": "Test builds for linux_x86_64", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_64-sanitizers-asan", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86_64", + "ci-target-linux_x86_64", + "ci-clang_gcc-sanitizers-asan" + ], + "displayName": "linux_x86_64-sanitizers-asan", + "description": "Address Sanitizer builds for linux_x86_64", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_64-sanitizers-ubsan", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86_64", + "ci-target-linux_x86_64", + "ci-clang_gcc-sanitizers-ubsan" + ], + "displayName": "linux_x86_64-sanitizers-ubsan", + "description": "Undefined Behavior Sanitizer builds for linux_x86_64", + "generator": "Ninja" + }, + { + "name": "ci-target-android", + "hidden": true, + "cacheVariables": { + "ANDROID_PLATFORM": "android-21", + "ANDROID_NDK": "$env{DKSDK_PROJECT_BASE}.ci/local/share/ndk/ndk/23.1.7779620", + "BUILD_HYGIENE": "DISABLED" + }, + "environment": { + "ANDROID_x_REASON": "https://developer.android.com/studio/projects/configure-cmake#call-cmake-cli", + "BUILD_HYGIENE_REASON": "Android has a stdlib.h that does not pass clang-tidy validation" + }, + "toolchainFile": "$env{DKSDK_PROJECT_BASE}.ci/local/share/ndk/ndk/23.1.7779620/build/cmake/android.toolchain.cmake" + }, + { + "name": "ci-target-android_arm32v7a", + "hidden": true, + "inherits": [ "ci-target-android" ], + "cacheVariables": { + "ANDROID_ABI": "armeabi-v7a" + } + }, + { + "name": "ci-target-android_arm64v8a", + "hidden": true, + "inherits": [ "ci-target-android" ], + "cacheVariables": { + "ANDROID_ABI": "arm64-v8a" + } + }, + { + "name": "ci-target-android_x86", + "hidden": true, + "inherits": [ "ci-target-android" ], + "cacheVariables": { + "ANDROID_ABI": "x86" + } + }, + { + "name": "ci-target-android_x86_64", + "hidden": true, + "inherits": [ "ci-target-android" ], + "cacheVariables": { + "ANDROID_ABI": "x86_64" + } + }, + { + "name": "ci-linux_x86_X_android_x86", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86", + "ci-target-android_x86" + ], + "displayName": "linux_x86 -> android_x86", + "description": "Cross-compiler of host linux_x86 to target android_x86", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_X_android_arm32v7a", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86", + "ci-target-android_arm32v7a" + ], + "displayName": "linux_x86 -> android_arm32v7a", + "description": "Cross-compiler of host linux_x86 to target android_arm32v7a", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_64_X_android_x86_64", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86_64", + "ci-target-android_x86_64" + ], + "displayName": "linux_x86_64 -> android_x86_64", + "description": "Cross-compiler of host linux_x86_64 to target android_x86_64", + "generator": "Ninja" + }, + { + "name": "ci-linux_x86_64_X_android_arm64v8a", + "inherits": [ + "ci-tests-configure", + "ci-host-linux_x86_64", + "ci-target-android_arm64v8a" + ], + "displayName": "linux_x86_64 -> android_arm64v8a", + "description": "Cross-compiler of host linux_x86_64 to target android_arm64v8a", + "generator": "Ninja" + }, + { + "name": "ci-windows_x86_64", + "inherits": [ + "ci-tests-configure", + "ci-host-windows_x86_64", + "ci-target-windows_x86_64" + ], + "displayName": "windows_x86_64", + "description": "Test builds for windows_x86_64", + "generator": "Ninja" + } + ], + "buildPresets": [ + { + "name": "ci-tests-build", + "hidden": true, + "configurePreset": "ci-tests-configure", + "configuration": "Release" + }, + { + "name": "ci-tests", + "inherits": "ci-tests-build", + "targets": ["all"] + } + ], + "testPresets": [ + { + "name": "ci-test", + "configurePreset": "ci-tests-configure" + } + ] +} diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 0000000..6f9ade1 --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1 @@ +set(VALGRIND_COMMAND_OPTIONS "--error-exitcode=109 --leak-check=full") diff --git a/README.md b/README.md index 15c9fdd..5637e76 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,16 @@ capnpc-c This is a C plugin for [Cap'n Proto](http://kentonv.github.io/capnproto), an efficient protocol for sharing data and capabilities. -## UNMAINTAINED +This is a fork of https://github.com/opensourcerouting/c-capnproto with support +for CMake and Windows, a build matrix that includes Android and Windows, and +fixes several bugs that start with the [CHANGES for version 0.9.0](./CHANGES.md#090). -This project is currently **NOT MAINTAINED**. If you are interested in -taking over maintenance and/or need this for some project, please look at -issue https://github.com/opensourcerouting/c-capnproto/issues/55 +The fork is maintained as part of [DkML](https://diskuv.com/dkmlbook/) +and [DkSDK](https://diskuv.com/cmake/help/latest/), but PRs are welcome from +anybody. If you are looking for your first PR, fixing the false positive +memory leaks in the test code would be great! -No releases will be made. PRs may sit unreviewed for multiple years. **PRs -MAY get merged WITHOUT ANY REVIEW, as a last ditch attempt to not waste -people's efforts on PRs. This means things may break completely.** - -> ## Security warning! +## Security warning! > The generated code assumes all input to be trusted. Do NOT use with > untrusted input! There is currently no code in place to check if @@ -28,27 +27,26 @@ this project and then you can utilize it as: capnpc compiler/test.capnp -oc ``` -[![Build Status](https://travis-ci.org/opensourcerouting/c-capnproto.svg?branch=master)](https://travis-ci.org/opensourcerouting/c-capnproto) - ## Building on Linux ```sh -git clone --recurse-submodules https://github.com/opensourcerouting/c-capnproto +git clone https://gitlab.com/diskuv-ocaml/ext/c-capnproto.git cd c-capnproto -autoreconf -f -i -s -./configure -make -make check +cmake --preset=ci-linux_x86_64 +cmake --build --preset=ci-tests ``` -## Building with Meson +## Building on Windows + +You will need Visual Studio 2019 installed. Other versions of Visual Studio may work; they simply haven't been tested. + +Once you have Visual Studio, run the `x64 Native Tools Command Prompt for VS 2019` and type the following: ```sh -git clone --recurse-submodules https://github.com/opensourcerouting/c-capnproto +git clone https://gitlab.com/diskuv-ocaml/ext/c-capnproto.git cd c-capnproto -meson setup build -meson compile -C build -build/capn-test +cmake --preset=ci-windows_x86_64 +cmake --build --preset=ci-tests ``` ## Usage @@ -111,8 +109,8 @@ The project [`quagga-capnproto`](https://github.com/opensourcerouting/quagga-cap ## Status -This is a merge of 3 forks of [James McKaskill's great -work](https://github.com/jmckaskill/c-capnproto), which has been untouched for +https://github.com/opensourcerouting/c-capnproto was a merge of 3 forks of [James McKaskill's great +work](https://github.com/jmckaskill/c-capnproto), which had been untouched for a while: - [liamstask's fork](https://github.com/liamstask/c-capnproto) diff --git a/ci/ctest/Sanitizers-ASAN-CTest.cmake b/ci/ctest/Sanitizers-ASAN-CTest.cmake new file mode 100644 index 0000000..9bbfdba --- /dev/null +++ b/ci/ctest/Sanitizers-ASAN-CTest.cmake @@ -0,0 +1,66 @@ +# Run locally the -asanSanitizer with: +# rm -rf build/ +# ./dk dksdk.cmake.link +# .ci/cmake/bin/cmake --preset=ci-linux_x86_64-sanitizers-asan +# .ci/cmake/bin/ctest -S ci/ctest/Sanitizers-ASAN-CTest.cmake --extra-verbose + +# Determine project directories +set(OUR_PROJECT_SOURCE_DIR "${CTEST_SCRIPT_DIRECTORY}/../..") +cmake_path(NORMAL_PATH OUR_PROJECT_SOURCE_DIR) +cmake_path(APPEND OUR_PROJECT_SOURCE_DIR build OUTPUT_VARIABLE OUR_PROJECT_BINARY_DIR) + +# Re-use test details +include(${OUR_PROJECT_SOURCE_DIR}/CTestConfig.cmake) + +# Read the CI generated CMakeCache.txt +load_cache("${OUR_PROJECT_BINARY_DIR}" + READ_WITH_PREFIX CACHED_ + CMAKE_BUILD_TYPE) + +# Basic information every run should set +site_name(CTEST_SITE) +set(CTEST_BUILD_NAME ${CMAKE_HOST_SYSTEM_NAME}) +set(CTEST_SOURCE_DIRECTORY "${OUR_PROJECT_SOURCE_DIR}") +set(CTEST_BINARY_DIRECTORY "${OUR_PROJECT_BINARY_DIR}") +set(CTEST_CMAKE_GENERATOR Ninja) +if(CACHED_CMAKE_BUILD_TYPE) + set(CTEST_CONFIGURATION_TYPE ${CACHED_CMAKE_BUILD_TYPE}) +else() + set(CTEST_CONFIGURATION_TYPE Debug) +endif() + +set(CTEST_MEMORYCHECK_TYPE AddressSanitizer) + +# ASAN_OPTIONS +# -------- +# +# Even if we have [ASAN_OPTIONS] defined in CMakePresets.json, +# that will not impact this script which is invoked by `ctest` not +# `cmake`, and [CTEST_MEMORYCHECK_TYPE] will overwrite it anyway. +# +# Valgrind makes ASAN memory leaks redundant. And the unforked +# c-capnproto code disabled memory leaks anyway. So we use the +# same options. +set(extra_OPTIONS detect_leaks=0,detect_odr_violation=0,allocator_may_return_null=1) +# Apply to ctest_memcheck() +set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS ${extra_OPTIONS}) +# Apply to ctest_build() +if(extra_OPTIONS) + if(ENV{ASAN_OPTIONS}) + set(ENV{ASAN_OPTIONS} ${extra_OPTIONS}:$ENV{ASAN_OPTIONS}) + else() + set(ENV{ASAN_OPTIONS} ${extra_OPTIONS}) + endif() +endif() + +ctest_start(Experimental) + +ctest_build(RETURN_VALUE err) +if(err) + message(FATAL_ERROR "CTest build error ${err}") +endif() + +ctest_memcheck(RETURN_VALUE err) +if(err) + message(FATAL_ERROR "CTest memcheck error ${err}") +endif() diff --git a/ci/ctest/Sanitizers-UBSAN-CTest.cmake b/ci/ctest/Sanitizers-UBSAN-CTest.cmake new file mode 100644 index 0000000..cca10d4 --- /dev/null +++ b/ci/ctest/Sanitizers-UBSAN-CTest.cmake @@ -0,0 +1,69 @@ +# Run locally the -ubsan Sanitizer with: +# rm -rf build/ +# ./dk dksdk.cmake.link +# .ci/cmake/bin/cmake --preset=ci-linux_x86_64-sanitizers-ubsan +# .ci/cmake/bin/ctest -S ci/ctest/Sanitizers-UBSAN-CTest.cmake --extra-verbose + +# Determine project directories +if(NOT OUR_PROJECT_SOURCE_DIR) + set(OUR_PROJECT_SOURCE_DIR "${CTEST_SCRIPT_DIRECTORY}/../..") + cmake_path(NORMAL_PATH OUR_PROJECT_SOURCE_DIR) +endif() +if(NOT OUR_PROJECT_BINARY_DIR) + cmake_path(APPEND OUR_PROJECT_SOURCE_DIR build OUTPUT_VARIABLE OUR_PROJECT_BINARY_DIR) +endif() + +# Re-use test details +include(${OUR_PROJECT_SOURCE_DIR}/CTestConfig.cmake) + +# Read the CI generated CMakeCache.txt +load_cache("${OUR_PROJECT_BINARY_DIR}" + READ_WITH_PREFIX CACHED_ + CMAKE_BUILD_TYPE) + +# Basic information every run should set +site_name(CTEST_SITE) +set(CTEST_BUILD_NAME ${CMAKE_HOST_SYSTEM_NAME}) +set(CTEST_SOURCE_DIRECTORY "${OUR_PROJECT_SOURCE_DIR}") +set(CTEST_BINARY_DIRECTORY "${OUR_PROJECT_BINARY_DIR}") +set(CTEST_CMAKE_GENERATOR Ninja) +if(CACHED_CMAKE_BUILD_TYPE) + set(CTEST_CONFIGURATION_TYPE ${CACHED_CMAKE_BUILD_TYPE}) +else() + set(CTEST_CONFIGURATION_TYPE Debug) +endif() + +# Tell CTest to add to UBSAN_OPTIONS to capture its logs +set(CTEST_MEMORYCHECK_TYPE UndefinedBehaviorSanitizer) + +# UBSAN_OPTIONS +# -------- +# +# Even if we have [UBSAN_OPTIONS] defined in CMakePresets.json, +# that will not impact this script which is invoked by `ctest` not +# `cmake`, and [CTEST_MEMORYCHECK_TYPE] will overwrite it anyway. +# +# Enable stack traces +set(extra_OPTIONS print_stacktrace=1) +# Apply to ctest_memcheck() +set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS ${extra_OPTIONS}) +# Apply to ctest_build() +if(extra_OPTIONS) + if(ENV{UBSAN_OPTIONS}) + set(ENV{UBSAN_OPTIONS} ${extra_OPTIONS}:$ENV{UBSAN_OPTIONS}) + else() + set(ENV{UBSAN_OPTIONS} ${extra_OPTIONS}) + endif() +endif() + +ctest_start(Experimental) + +ctest_build(RETURN_VALUE err) +if(err) + message(FATAL_ERROR "CTest build error ${err}") +endif() + +ctest_memcheck(RETURN_VALUE err) +if(err) + message(FATAL_ERROR "CTest memcheck error ${err}") +endif() diff --git a/ci/gitlab/test.gitlab-ci.yml b/ci/gitlab/test.gitlab-ci.yml new file mode 100644 index 0000000..39181dc --- /dev/null +++ b/ci/gitlab/test.gitlab-ci.yml @@ -0,0 +1,155 @@ +.unit-test: + rules: + - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "next"' + artifacts: + paths: + - build/Testing/Temporary/LastBuild_*.log + - build/Testing/Temporary/LastTest.log + - build/Testing/Temporary/LastTests_*.log + - build/Testing/Temporary/MemoryChecker.*.log + reports: + junit: + - build/cmakespec.xml + - build/tests/*-Results.xml + when: always + +unit-test-debian: + stage: test + # The original c-capnproto unit tests were full of memory leaks (not closing test + # structures). Sigh. Until those are fixed, we can't detect real memory leaks. + allow_failure: true + extends: + - .c-cmake-debian:before + - .unit-test + script: + - export PATH="$PWD/.ci/cmake/bin:$PATH" + + - echo -e "\e[0Ksection_start:`date +%s`:configure[collapsed=true]\r\e[0KConfiguring build scripts" + - rm -rf build/ + - cmake --preset=ci-linux_x86_64 -D BUILD_HYGIENE=ENABLED + - echo -e "\e[0Ksection_end:`date +%s`:configure\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:build[collapsed=true]\r\e[0KBuilding test targets" + - cmake --build --preset=ci-tests + - echo -e "\e[0Ksection_end:`date +%s`:build\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:unittest[collapsed=true]\r\e[0KUnit Testing" + - ctest --output-junit cmakespec.xml --verbose --preset=ci-test + - echo -e "\e[0Ksection_end:`date +%s`:unittest\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:memcheck[collapsed=true]\r\e[0KMemory Testing" + - ctest -T memcheck --test-dir build --verbose + - echo -e "\e[0Ksection_end:`date +%s`:memcheck\r\e[0K" + +unit-test-android_x86_64: + stage: test + extends: + - .c-cmake-debian:before + - .unit-test + script: + - export PATH="$PWD/.ci/cmake/bin:$PATH" + + - echo -e "\e[0Ksection_start:`date +%s`:installandroid[collapsed=true]\r\e[0KInstalling Android NDK" + - ./dk dksdk.android.ndk.download + - echo -e "\e[0Ksection_end:`date +%s`:installandroid\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:configure[collapsed=true]\r\e[0KConfiguring build scripts" + - rm -rf build/ + - cmake --preset=ci-linux_x86_64_X_android_x86_64 + - echo -e "\e[0Ksection_end:`date +%s`:configure\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:build[collapsed=true]\r\e[0KBuilding test targets" + - cmake --build --preset=ci-tests + - echo -e "\e[0Ksection_end:`date +%s`:build\r\e[0K" + + - echo 'No unit tests and no memory tests for a cross-compiled target' + +unit-test-windows: + stage: test + extends: + - .c-cmake-windows:before + - .unit-test + script: + - $env:Path += ';C:\Program Files\CMake\bin' + + - $esc="$([char]27)"; $cr="$([char]13)"; $TXT_SECTION="${esc}[36m"; $TXT_CLEAR="${esc}[0m" + - | + function Get-CurrentEpochSecs { + [long]$timestamp = [math]::Round((([datetime]::UtcNow) - (Get-Date -Date '1/1/1970')).TotalMilliseconds) + [math]::Round($timestamp / 1000) + } + + - Write-Host "${esc}[0Ksection_start:$(Get-CurrentEpochSecs):configure[collapsed=true]${cr}${esc}[0K"$TXT_SECTION"Configuring build scripts" + - if (Test-Path build) { Remove-Item -Recurse -Force build } + # Linux can test with BUILD_HYGIENE=ENABLED. Don't want to install clang-tidy through + # Chocolatey because huge LLVM download (`choco install llvm`). + - ci/run-with-msvc.cmd cmake --preset=ci-windows_x86_64 -D BUILD_HYGIENE=DISABLED + - Write-Host "${esc}[0Ksection_end:$(Get-CurrentEpochSecs):configure${cr}${esc}[0K" + + - Write-Host "${esc}[0Ksection_start:$(Get-CurrentEpochSecs):build[collapsed=true]${cr}${esc}[0K"$TXT_SECTION"Building test targets" + - ci/run-with-msvc.cmd cmake --build --preset=ci-tests + - Write-Host "${esc}[0Ksection_end:$(Get-CurrentEpochSecs):build${cr}${esc}[0K" + + - Write-Host "${esc}[0Ksection_start:$(Get-CurrentEpochSecs):unittest[collapsed=true]${cr}${esc}[0K"$TXT_SECTION"Unit Testing" + - ci/run-with-msvc.cmd ctest --output-junit cmakespec.xml --verbose --preset=ci-test + - Write-Host "${esc}[0Ksection_end:$(Get-CurrentEpochSecs):unittest${cr}${esc}[0K" + +sanitizers-debian-asan: + stage: test + extends: + - .c-cmake-debian:before + rules: + - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "next"' + artifacts: + paths: + - build/Testing/Temporary/LastBuild_*.log + - build/Testing/Temporary/LastDynamicAnalysis_*.log + - build/Testing/Temporary/LastTest.log + - build/Testing/Temporary/LastTests_*.log + - build/Testing/Temporary/MemoryChecker.*.log + reports: + junit: + - build/cmakespec.xml + - build/tests/*-Results.xml + when: always + script: + - export PATH="$PWD/.ci/cmake/bin:$PATH" + + - echo -e "\e[0Ksection_start:`date +%s`:configure[collapsed=true]\r\e[0KConfiguring build scripts" + - rm -rf build/ + - cmake --preset=ci-linux_x86_64-sanitizers-asan + - echo -e "\e[0Ksection_end:`date +%s`:configure\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:build[collapsed=true]\r\e[0KRunning ASAN sanitizers build and check" + - ctest -S ci/ctest/Sanitizers-ASAN-CTest.cmake + - echo -e "\e[0Ksection_end:`date +%s`:build\r\e[0K" + +sanitizers-debian-ubsan: + stage: test + extends: + - .c-cmake-debian:before + rules: + - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "next"' + artifacts: + paths: + - build/Testing/Temporary/LastBuild_*.log + - build/Testing/Temporary/LastDynamicAnalysis_*.log + - build/Testing/Temporary/LastTest.log + - build/Testing/Temporary/LastTests_*.log + - build/Testing/Temporary/MemoryChecker.*.log + reports: + junit: + - build/cmakespec.xml + - build/tests/*-Results.xml + when: always + script: + - export PATH="$PWD/.ci/cmake/bin:$PATH" + + - echo -e "\e[0Ksection_start:`date +%s`:configure[collapsed=true]\r\e[0KConfiguring build scripts" + - rm -rf build/ + - cmake --preset=ci-linux_x86_64-sanitizers-ubsan + - echo -e "\e[0Ksection_end:`date +%s`:configure\r\e[0K" + + - echo -e "\e[0Ksection_start:`date +%s`:build[collapsed=true]\r\e[0KRunning UBSAN sanitizers build and check" + - ctest -S ci/ctest/Sanitizers-UBSAN-CTest.cmake + - echo -e "\e[0Ksection_end:`date +%s`:build\r\e[0K" diff --git a/ci/run-with-msvc.cmd b/ci/run-with-msvc.cmd new file mode 100644 index 0000000..25c3c05 --- /dev/null +++ b/ci/run-with-msvc.cmd @@ -0,0 +1,3 @@ +CALL "%VSDIR%\VC\Auxiliary\Build\vcvars64.bat" +ECHO ON +%* \ No newline at end of file diff --git a/cmake/FindDkToolScripts.cmake b/cmake/FindDkToolScripts.cmake new file mode 100644 index 0000000..988c92a --- /dev/null +++ b/cmake/FindDkToolScripts.cmake @@ -0,0 +1,88 @@ +# Recommendation: Place this file in source control. +# Auto-generated by `./dk dksdk.project.new` of DkHelloWorld. + +include(FetchContent) + +function(parse_dktool_command_line) + # The first argument is . All dots will be replaced with a + # triple underscore as a convenience and to be pretty for the user. + if(ARGC EQUAL 0) + message(FATAL_ERROR "Missing . Usage: ./dk [args]") + endif() + set(command ${ARGV0}) + string(REPLACE "." "___" function_name ${command}) + + # Set policies (we are in a new EVAL CODE context) + # Included scripts do automatic cmake_policy PUSH and POP + if(POLICY CMP0011) + cmake_policy(SET CMP0011 NEW) + endif() + + # Setup the binary directory + if(NOT DKTOOL_WORKDIR) + message(FATAL_ERROR "Illegal state. Expecting DKTOOL_WORKDIR") + endif() + set(CMAKE_BINARY_DIR ${DKTOOL_WORKDIR}) + set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_BINARY_DIR}) + + # Include all the user scripts + file(GLOB_RECURSE command_files LIST_DIRECTORIES FALSE + cmake/scripts/*.cmake) + foreach(command_file IN LISTS command_files) + include(${command_file}) + endforeach() + + # Include all the system scripts. + # - Since the system scripts come after the user scripts, the user scripts + # don't override the system scripts unless the user scripts use deferred + # hooks or redefine CMake built-in functions. + if(NOT IS_DIRECTORY cmake/scripts/dksdk) + # If this project (ex. DkHelloWorld) has the system scripts, it must + # have all of them. Otherwise we download the system scripts. + FetchContent_Populate(DkHelloWorld + QUIET + GIT_REPOSITORY https://gitlab.com/diskuv/samples/DkHelloWorld.git + GIT_TAG 1.0 + ) + file(GLOB_RECURSE system_command_files LIST_DIRECTORIES FALSE + ${dkhelloworld_SOURCE_DIR}/cmake/scripts/dksdk/*.cmake) + list(APPEND command_files ${system_command_files}) + foreach(command_file IN LISTS system_command_files) + include(${command_file}) + endforeach() + endif() + + # Validate the exists + if(NOT COMMAND ${function_name}) + set(pretty_command_files ${command_files}) + list(TRANSFORM pretty_command_files PREPEND " ") + list(TRANSFORM pretty_command_files APPEND "\n") + string(JOIN "" str_pretty_command_files ${pretty_command_files}) + message(FATAL_ERROR "No command '${command}' exists. The function '${function_name}' was searched in the following locations: +${str_pretty_command_files}") + endif() + + # Parse the remainder of the arguments [args] + # * Use technique from [Professional CMake: A Practical Guide - Forwarding Command Arguments] + # to forward arguments correctly to an inner function (the function). + cmake_parse_arguments(PARSE_ARGV 1 FWD "" "" "") + set(quotedArgs "") + foreach(arg IN LISTS FWD_UNPARSED_ARGUMENTS) + string(APPEND quotedArgs " [===[${arg}]===]") + endforeach() + + # Call the function + cmake_language(EVAL CODE "${function_name}(${quotedArgs})") +endfunction() + +# DkSDK data home +if(WIN32) + set(DKSDK_DATA_HOME "$ENV{LOCALAPPDATA}/Programs/DkSDK") +elseif(DEFINED ENV{XDG_DATA_HOME}) + set(DKSDK_DATA_HOME "$ENV{XDG_DATA_HOME}/dksdk") +else() + set(DKSDK_DATA_HOME "$ENV{HOME}/.local/share/dksdk") +endif() + +# Splat DKTOOL_CMDLINE +cmake_language(EVAL CODE "parse_dktool_command_line(${DKTOOL_CMDLINE})") diff --git a/dk b/dk new file mode 100755 index 0000000..23df517 --- /dev/null +++ b/dk @@ -0,0 +1,701 @@ +#!/bin/sh +# Recommendation: Place this file in source control. +# Auto-generated by `./dk dksdk.project.new` of DkHelloWorld. +# +# Invoking: ./dk +# That works in Powershell on Windows, and in Unix. Copy-and-paste works! +# +# Purpose: Install CMake if not already. Then invoke CMake. + +set -euf + +# --- Imports of dkml-runtime-common's crossplatform-functions.sh --- + +# Get standard locations of Unix system binaries like `/usr/bin/mv` (or `/bin/mv`). +# +# Will not return anything in `/usr/local/bin` or `/usr/sbin`. Use when you do not +# know whether the PATH has been set correctly, or when you do not know if the +# system binary exists. +# +# At some point in the future, this function will error out if the required system binaries +# do not exist. Most system binaries are common to all Unix/Linux/macOS installations but +# some (like `comm`) may need to be installed for proper functioning of DKML. +# +# Outputs: +# - env:DKMLSYS_MV - Location of `mv` +# - env:DKMLSYS_CHMOD - Location of `chmod` +# - env:DKMLSYS_UNAME - Location of `uname` +# - env:DKMLSYS_ENV - Location of `env` +# - env:DKMLSYS_AWK - Location of `awk` +# - env:DKMLSYS_SED - Location of `sed` +# - env:DKMLSYS_COMM - Location of `comm` +# - env:DKMLSYS_INSTALL - Location of `install` +# - env:DKMLSYS_RM - Location of `rm` +# - env:DKMLSYS_SORT - Location of `sort` +# - env:DKMLSYS_CAT - Location of `cat` +# - env:DKMLSYS_STAT - Location of `stat` +# - env:DKMLSYS_GREP - Location of `grep` +# - env:DKMLSYS_CURL - Location of `curl` (empty if not found) +# - env:DKMLSYS_WGET - Location of `wget` (empty if not found) +# - env:DKMLSYS_TR - Location of `tr` +autodetect_system_binaries() { + if [ -z "${DKMLSYS_MV:-}" ]; then + if [ -x /usr/bin/mv ]; then + DKMLSYS_MV=/usr/bin/mv + else + DKMLSYS_MV=/bin/mv + fi + fi + if [ -z "${DKMLSYS_CHMOD:-}" ]; then + if [ -x /usr/bin/chmod ]; then + DKMLSYS_CHMOD=/usr/bin/chmod + else + DKMLSYS_CHMOD=/bin/chmod + fi + fi + if [ -z "${DKMLSYS_UNAME:-}" ]; then + if [ -x /usr/bin/uname ]; then + DKMLSYS_UNAME=/usr/bin/uname + else + DKMLSYS_UNAME=/bin/uname + fi + fi + if [ -z "${DKMLSYS_ENV:-}" ]; then + if [ -x /usr/bin/env ]; then + DKMLSYS_ENV=/usr/bin/env + else + DKMLSYS_ENV=/bin/env + fi + fi + if [ -z "${DKMLSYS_AWK:-}" ]; then + if [ -x /usr/bin/awk ]; then + DKMLSYS_AWK=/usr/bin/awk + else + DKMLSYS_AWK=/bin/awk + fi + fi + if [ -z "${DKMLSYS_SED:-}" ]; then + if [ -x /usr/bin/sed ]; then + DKMLSYS_SED=/usr/bin/sed + else + DKMLSYS_SED=/bin/sed + fi + fi + if [ -z "${DKMLSYS_COMM:-}" ]; then + if [ -x /usr/bin/comm ]; then + DKMLSYS_COMM=/usr/bin/comm + else + DKMLSYS_COMM=/bin/comm + fi + fi + if [ -z "${DKMLSYS_INSTALL:-}" ]; then + if [ -x /usr/bin/install ]; then + DKMLSYS_INSTALL=/usr/bin/install + else + DKMLSYS_INSTALL=/bin/install + fi + fi + if [ -z "${DKMLSYS_RM:-}" ]; then + if [ -x /usr/bin/rm ]; then + DKMLSYS_RM=/usr/bin/rm + else + DKMLSYS_RM=/bin/rm + fi + fi + if [ -z "${DKMLSYS_SORT:-}" ]; then + if [ -x /usr/bin/sort ]; then + DKMLSYS_SORT=/usr/bin/sort + else + DKMLSYS_SORT=/bin/sort + fi + fi + if [ -z "${DKMLSYS_CAT:-}" ]; then + if [ -x /usr/bin/cat ]; then + DKMLSYS_CAT=/usr/bin/cat + else + DKMLSYS_CAT=/bin/cat + fi + fi + if [ -z "${DKMLSYS_STAT:-}" ]; then + if [ -x /usr/bin/stat ]; then + DKMLSYS_STAT=/usr/bin/stat + else + DKMLSYS_STAT=/bin/stat + fi + fi + if [ -z "${DKMLSYS_GREP:-}" ]; then + if [ -x /usr/bin/grep ]; then + DKMLSYS_GREP=/usr/bin/grep + else + DKMLSYS_GREP=/bin/grep + fi + fi + if [ -z "${DKMLSYS_CURL:-}" ]; then + if [ -x /usr/bin/curl ]; then + DKMLSYS_CURL=/usr/bin/curl + elif [ -x /bin/curl ]; then + DKMLSYS_CURL=/bin/curl + else + DKMLSYS_CURL= + fi + fi + if [ -z "${DKMLSYS_WGET:-}" ]; then + if [ -x /usr/bin/wget ]; then + DKMLSYS_WGET=/usr/bin/wget + elif [ -x /bin/wget ]; then + DKMLSYS_WGET=/bin/wget + else + DKMLSYS_WGET= + fi + fi + if [ -z "${DKMLSYS_TR:-}" ]; then + if [ -x /usr/bin/tr ]; then + DKMLSYS_TR=/usr/bin/tr + else + DKMLSYS_TR=/bin/tr + fi + fi + export DKMLSYS_MV DKMLSYS_CHMOD DKMLSYS_UNAME DKMLSYS_ENV DKMLSYS_AWK DKMLSYS_SED DKMLSYS_COMM DKMLSYS_INSTALL + export DKMLSYS_RM DKMLSYS_SORT DKMLSYS_CAT DKMLSYS_STAT DKMLSYS_GREP DKMLSYS_CURL DKMLSYS_WGET DKMLSYS_TR +} + +# Is a Windows build machine if we are in a MSYS2 or Cygwin environment. +# +# Better alternatives +# ------------------- +# +# 1. If you are checking to see if you should do a cygpath, then just guard it +# like so: +# if [ -x /usr/bin/cygpath ]; then +# do_something $(/usr/bin/cygpath ...) ... +# fi +# This clearly guards what you are about to do (cygpath) with what you will +# need (cygpath). +# 2. is_arg_windows_platform +is_unixy_windows_build_machine() { + if is_msys2_msys_build_machine || is_cygwin_build_machine; then + return 0 + fi + return 1 +} + +# Is a MSYS2 environment with the MSYS or MINGW64 subsystem? +# * MSYS2 can also do MinGW 32-bit and 64-bit subsystems. Used by Diskuv OCaml +# * MINGW64 used by Git Bash (aka. GitHub Actions `shell: bash`) +# https://www.msys2.org/docs/environments/ +is_msys2_msys_build_machine() { + if [ -e /usr/bin/msys-2.0.dll ] && { + [ "${MSYSTEM:-}" = "MSYS" ] || [ "${MSYSTEM:-}" = "MINGW64" ] || [ "${MSYSTEM:-}" = "UCRT64" ] || [ "${MSYSTEM:-}" = "CLANG64" ] || [ "${MSYSTEM:-}" = "MINGW32" ] || [ "${MSYSTEM:-}" = "CLANG32" ] || [ "${MSYSTEM:-}" = "CLANGARM64" ] + }; then + return 0 + fi + return 1 +} + +is_cygwin_build_machine() { + if [ -e /usr/bin/cygwin1.dll ]; then + return 0 + fi + return 1 +} + +# Tries to find the host ABI. +# +# Beware: This function uses `uname` probing which is inaccurate during +# cross-compilation. +# +# Outputs: +# - env:BUILDHOST_ARCH will contain the host ABI. +autodetect_buildhost_arch() { + # Set DKMLSYS_* + autodetect_system_binaries + + autodetect_buildhost_arch_SYSTEM=$("$DKMLSYS_UNAME" -s) + autodetect_buildhost_arch_MACHINE=$("$DKMLSYS_UNAME" -m) + # list from https://en.wikipedia.org/wiki/Uname and https://stackoverflow.com/questions/45125516/possible-values-for-uname-m + case "${autodetect_buildhost_arch_SYSTEM}-${autodetect_buildhost_arch_MACHINE}" in + Linux-armv7*) + BUILDHOST_ARCH=linux_arm32v7;; + Linux-armv6* | Linux-arm) + BUILDHOST_ARCH=linux_arm32v6;; + Linux-aarch64 | Linux-arm64 | Linux-armv8*) + BUILDHOST_ARCH=linux_arm64;; + Linux-i386 | Linux-i686) + BUILDHOST_ARCH=linux_x86;; + Linux-x86_64) + BUILDHOST_ARCH=linux_x86_64;; + Darwin-arm64) + BUILDHOST_ARCH=darwin_arm64;; + Darwin-x86_64) + BUILDHOST_ARCH=darwin_x86_64;; + *-i386 | *-i686) + if is_unixy_windows_build_machine; then + BUILDHOST_ARCH=windows_x86 + else + printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2 + exit 1 + fi + ;; + *-x86_64) + if is_unixy_windows_build_machine; then + BUILDHOST_ARCH=windows_x86_64 + else + printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2 + exit 1 + fi + ;; + *) + # Since: + # 1) MSYS2 does not run on ARM/ARM64 (https://www.msys2.org/docs/environments/) + # 2) MSVC does not use ARM/ARM64 as host machine (https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160) + # we do not support Windows ARM/ARM64 as a build machine + printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2 + exit 1 + ;; + esac +} + +# A function that will try to print an ISO8601 timestamp, but will fallback to +# the system default. Always uses UTC timezone. +try_iso8601_timestamp() { + date -u -Iseconds 2>/dev/null || TZ=UTC date +} + +# A function that will print the command and possibly time it (if and only if it uses a full path to +# an executable, so that 'time' does not fail on internal shell functions). +# If --return-error-code is the first argument or LOG_TRACE_RETURN_ERROR_CODE=ON, then instead of exiting the +# function will return the error code. +log_trace() { + log_trace_RETURN=${LOG_TRACE_RETURN_ERROR_CODE:-OFF} + + log_trace_1="$1" + if [ "$log_trace_1" = "--return-error-code" ]; then + shift + log_trace_RETURN=ON + fi + + if [ "${DKML_BUILD_TRACE:-OFF}" = ON ]; then + printf "[%s] %s\n" "$(try_iso8601_timestamp)" "+ $*" >&2 + if [ -x "$1" ]; then + time "$@" + else + "$@" + fi + else + # use judgement so we essentially have log at an INFO level + case "$1" in + rm|cp) + # debug level. only show when DKML_BUILD_TRACE=ON + ;; + git|make|ocaml_configure|ocaml_make|make_host|make_target) + # info level. and can show entire command without polluting the screen + printf "[%s] %s\n" "$(try_iso8601_timestamp)" "$*" >&2 + ;; + *) printf "[%s] %s\n" "$(try_iso8601_timestamp)" "$1" >&2 + esac + "$@" + fi + log_trace_ec="$?" + if [ "$log_trace_ec" -ne 0 ]; then + if [ "$log_trace_RETURN" = ON ]; then + return "$log_trace_ec" + else + printf "FATAL: Command failed with exit code %s: %s\n" "$log_trace_ec" "$*" >&2 + exit "$log_trace_ec" + fi + fi +} + +# [sha256compute FILE] writes the SHA256 checksum (hex encoded) of file FILE to the standard output. +sha256compute() { + sha256compute_FILE="$1" + shift + # For reasons unclear doing the following in MSYS2: + # sha256sum 'Z:\source\README.md' + # will produce a backslash like: + # \5518c76ed7234a153941fb7bc94b6e91d9cb8f1c4e22daf169a59b5878c3fc8a *Z:\\source\\README.md + # So always cygpath the filename if available + if [ -x /usr/bin/cygpath ]; then + sha256compute_FILE=$(/usr/bin/cygpath -a "$sha256compute_FILE") + fi + + if [ -x /usr/bin/shasum ]; then + /usr/bin/shasum -a 256 "$sha256compute_FILE" | awk '{print $1}' + elif [ -x /usr/bin/sha256sum ]; then + /usr/bin/sha256sum "$sha256compute_FILE" | awk '{print $1}' + else + printf "FATAL: %s\n" "No sha256 checksum utility found" >&2 + exit 107 + fi +} + +# [sha256check FILE SUM] checks that the file FILE has a SHA256 checksum (hex encoded) of SUM. +# The function will return nonzero (and exit with failure if `set -e` is enabled) if the checksum does not match. +sha256check() { + sha256check_FILE="$1" + shift + sha256check_SUM="$1" + shift + if [ -x /usr/bin/shasum ]; then + printf "%s %s" "$sha256check_SUM" "$sha256check_FILE" | /usr/bin/shasum -a 256 -c >&2 + elif [ -x /usr/bin/sha256sum ]; then + printf "%s %s" "$sha256check_SUM" "$sha256check_FILE" | /usr/bin/sha256sum -c >&2 + else + printf "FATAL: %s\n" "No sha256 checksum utility found" >&2 + exit 107 + fi +} + +# [downloadfile URL FILE SUM] downloads from URL into FILE and verifies the SHA256 checksum of SUM. +# If the FILE already exists with the correct checksum it is not redownloaded. +# The function will exit with failure if the checksum does not match. +downloadfile() { + downloadfile_URL="$1" + shift + downloadfile_FILE="$1" + shift + downloadfile_SUM="$1" + shift + + # Set DKMLSYS_* + autodetect_system_binaries + + if [ -e "$downloadfile_FILE" ]; then + if sha256check "$downloadfile_FILE" "$downloadfile_SUM"; then + return 0 + else + $DKMLSYS_RM -f "$downloadfile_FILE" + fi + fi + if [ "${CI:-}" = true ]; then + if [ -n "$DKMLSYS_CURL" ]; then + log_trace "$DKMLSYS_CURL" -L -s "$downloadfile_URL" -o "$downloadfile_FILE".tmp + elif [ -n "$DKMLSYS_WGET" ]; then + log_trace "$DKMLSYS_WGET" -q -O "$downloadfile_FILE".tmp "$downloadfile_URL" + else + echo "No curl or wget available on the system paths" >&2 + exit 107 + fi + else + if [ -n "$DKMLSYS_CURL" ]; then + log_trace "$DKMLSYS_CURL" -L "$downloadfile_URL" -o "$downloadfile_FILE".tmp + elif [ -n "$DKMLSYS_WGET" ]; then + log_trace "$DKMLSYS_WGET" -O "$downloadfile_FILE".tmp "$downloadfile_URL" + else + echo "No curl or wget available on the system paths" >&2 + exit 107 + fi + fi + if ! sha256check "$downloadfile_FILE".tmp "$downloadfile_SUM"; then + printf "%s\n" "FATAL: Encountered a corrupted or compromised download from $downloadfile_URL" >&2 + exit 1 + fi + $DKMLSYS_MV "$downloadfile_FILE".tmp "$downloadfile_FILE" +} + +# --- Environment detection --- + +# Set DKMLSYS_* +autodetect_system_binaries + +# Find host ABI. Set in BUILDHOST_ARCH +autodetect_buildhost_arch + +# Use the project tree as the current directory +PROJ_DIR=$(dirname "$0") +PROJ_DIR=$(cd "$PROJ_DIR" && pwd) +cd "$PROJ_DIR" + +# --- Tool directory selection --- + +tools_dir= +tools_name=dktool +# 1. Check if CI since many CI providers can only cache content in a subdirectory +# of the project. +if [ -z "$tools_dir" ] && [ "${CI:-}" = true ]; then + install -d "$PROJ_DIR/.tools" + tools_dir="$PROJ_DIR/.tools" +fi +# 2. Check in locations rooted under /opt/diskuv +# We look under a /opt/diskuv early because +# - Especially important for WSL2 to use a pure Linux filesystem (ext4) for +# best performance. +# - Using a canonical location (especially /opt/diskuv/usr/share) makes +# it easy to use CMake presets for non-Windows hosts. +if [ -z "$tools_dir" ] && [ -n "${XDG_DATA_HOME:-}" ] && [ -w "/opt/diskuv/$XDG_DATA_HOME" ]; then + install -d "/opt/diskuv/$XDG_DATA_HOME/$tools_name" + tools_dir="/opt/diskuv/$XDG_DATA_HOME/$tools_name" +fi +if [ -z "$tools_dir" ] && [ -n "${HOME:-}" ] && [ -w "/opt/diskuv/$HOME" ]; then + install -d "/opt/diskuv/$HOME/.local/share/$tools_name" + tools_dir="/opt/diskuv/$HOME/.local/share/$tools_name" +fi +if [ -z "$tools_dir" ] && [ -w "/opt/diskuv/usr/share" ]; then + install -d "/opt/diskuv/usr/share/$tools_name" + tools_dir="/opt/diskuv/usr/share/$tools_name" +fi +# 3. Check in the conventional locations rooted under / +if [ -z "$tools_dir" ] && [ -n "${XDG_DATA_HOME:-}" ] && [ -w "$XDG_DATA_HOME" ]; then + install -d "$XDG_DATA_HOME/$tools_name" + tools_dir="$XDG_DATA_HOME/$tools_name" +fi +if [ -z "$tools_dir" ] && [ -n "${HOME:-}" ] && [ -w "$HOME" ]; then + install -d "$HOME/.local/share/$tools_name" + tools_dir="$HOME/.local/share/$tools_name" +fi +# 4. Validate +if [ -z "$tools_dir" ]; then + echo "FATAL: Could not find a location to install the tools necessary for this project." >&2 + echo " ...: Make sure you have a home directory and that it is write-able, or define" >&2 + echo " ...: the environment variable XDG_DATA_HOME in a shell profile script after" >&2 + echo " ...: creating the \$XDG_DATA_HOME directory." >&2 + exit 2 +fi + +# --- Tool downloads and installs --- + +# PREREQS +# ------- + +install_linux_prog() { + install_linux_prog_NAME=$1 + shift + install_linux_prog_PKG=$1 + shift + if [ -x "/usr/bin/$install_linux_prog_NAME" ]; then + export DK_PROG_INSTALLED_LOCATION="/usr/bin/$install_linux_prog_NAME" + else + if command -v yum > /dev/null 2> /dev/null; then + if [ "$(id -u)" -eq 0 ]; then + yum install -y "$install_linux_prog_PKG" + else + echo "Running: sudo yum install -y $install_linux_prog_PKG" + sudo yum install -y "$install_linux_prog_PKG" + fi + else + if [ "$(id -u)" -eq 0 ]; then + apt-get -q install -y "$install_linux_prog_PKG" + else + echo "Running: sudo -q apt-get -qq install -y --no-install-suggests $install_linux_prog_PKG" + sudo apt-get -qq install -y --no-install-suggests "$install_linux_prog_PKG" + fi + fi + DK_PROG_INSTALLED_LOCATION=$(command -v "$install_linux_prog_NAME") + export DK_PROG_INSTALLED_LOCATION + fi +} + +get_homebrew_binary() { + get_homebrew_binary_NAME=$1 + shift + if command -v brew > /dev/null 2> /dev/null; then + get_homebrew_binary_PREFIX=$(brew --prefix) + if [ -x "$get_homebrew_binary_PREFIX/bin/$get_homebrew_binary_NAME" ]; then + export DK_PROG_INSTALLED_LOCATION="$get_homebrew_binary_PREFIX/bin/$get_homebrew_binary_NAME" + return 0 + fi + fi + return 1 +} + +install_macos_prog() { + install_macos_prog_NAME=$1 + shift + install_macos_prog_PKG=$1 + shift + if [ -x "/usr/bin/$install_macos_prog_NAME" ]; then + export DK_PROG_INSTALLED_LOCATION="/usr/bin/$install_macos_prog_NAME" + elif [ -x "/usr/local/bin/$install_macos_prog_NAME" ]; then + export DK_PROG_INSTALLED_LOCATION="/usr/local/bin/$install_macos_prog_NAME" + elif get_homebrew_binary "$install_macos_prog_NAME"; then + # DK_PROG_INSTALLED_LOCATION already set by [get_homebrew_binary] + true + else + if command -v brew > /dev/null 2> /dev/null; then + brew install --quiet --formula "$install_macos_prog_PKG" >&2 + get_homebrew_binary "$install_macos_prog_NAME" + # DK_PROG_INSTALLED_LOCATION already set by [get_homebrew_binary] + elif command -v port > /dev/null 2> /dev/null; then + if [ "$(id -u)" -eq 0 ]; then + port install "$install_macos_prog_PKG" + else + echo "Running: sudo port install $install_macos_prog_PKG" + sudo port install "$install_macos_prog_PKG" + fi + DK_PROG_INSTALLED_LOCATION=$(command -v "$install_macos_prog_NAME") + export DK_PROG_INSTALLED_LOCATION + else + echo "FATAL: Neither Homebrew nor MacPorts are available on your macOS. You can follow https://docs.brew.sh/Installation to install Homebrew." >&2 + exit 2 + fi + fi +} + +case $BUILDHOST_ARCH in + linux_*) + install_linux_prog wget wget # For [downloadfile] + install_linux_prog tar tar # For handling tar balls later in this script + ;; +esac + +# NINJA +# ----- +# We need a valid CMAKE_GENERATOR to do FetchContent_Populate() in script mode + +NINJA_EXE= +case $BUILDHOST_ARCH in + darwin_*) + install_macos_prog ninja ninja + NINJA_EXE=$DK_PROG_INSTALLED_LOCATION;; + linux_*) + install_linux_prog ninja ninja-build + NINJA_EXE=$DK_PROG_INSTALLED_LOCATION;; +esac + +# CMAKE +# ----- + +case $BUILDHOST_ARCH in + linux_*) + # This is for CMake to do FetchContent() + install_linux_prog git git ;; +esac +case $BUILDHOST_ARCH in + linux_x86) + # This is for Python wheel extraction + install_linux_prog unzip unzip ;; +esac + +cmake_base= +cmake_majmin_ver=3.25 +cmake_majminpat_ver=3.25.2 +cmake_bindir= +cmake_destdir=$tools_dir/cmake-$cmake_majminpat_ver +install -d "$tools_dir/dl" +download_cmake() { + case $BUILDHOST_ARCH in + darwin_*) + install_macos_prog cmake cmake + cmake_bindir=$(dirname "$DK_PROG_INSTALLED_LOCATION") + ;; + linux_x86_64) + cmake_base="cmake-$cmake_majminpat_ver-linux-x86_64" + printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux x86_64" >&2 + downloadfile \ + "https://github.com/Kitware/CMake/releases/download/v$cmake_majminpat_ver/$cmake_base.tar.gz" \ + "$tools_dir/dl/cmake.tar.gz" \ + 783da74f132fd1fea91b8236d267efa4df5b91c5eec1dea0a87f0cf233748d99 + cmake_bindir="$cmake_destdir/bin" ;; + linux_x86) + # CMake does not provide 32-bit binaries. But pypi does at https://pypi.org/project/cmake/ + printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux x86" >&2 + downloadfile \ + https://files.pythonhosted.org/packages/11/6e/aeeddf2f5b16542b6a30ceab4896421e8705d8e9a9296dba79395db11b00/cmake-3.25.2-py2.py3-none-manylinux_2_17_i686.manylinux2014_i686.whl \ + "$tools_dir/dl/cmake.whl" \ + 715ef82e81b48db3e4c7744614c15ff361d53f6987fd70b1b66b0880595f2e2c + cmake_bindir="$cmake_destdir/bin" ;; + linux_arm64) + cmake_base="cmake-$cmake_majminpat_ver-linux-aarch64" + printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux ARM64" >&2 + downloadfile \ + "https://github.com/Kitware/CMake/releases/download/v$cmake_majminpat_ver/$cmake_base.tar.gz" \ + "$tools_dir/dl/cmake.tar.gz" \ + 9216ecf0449ade700e66e0def11eeaebf9fa7d4428c02f49cb59f11418d3f8a5 + cmake_bindir="$cmake_destdir/bin" ;; + esac +} +export_cmake_vars() { + case $BUILDHOST_ARCH in + darwin_*) + if command -v brew > /dev/null 2> /dev/null; then + cmake_bindir=$(brew --prefix cmake)/bin + else + cmake_bindir=$(command -v cmake) + cmake_bindir=$(dirname "$cmake_bindir") + fi + ;; + linux_x86_64) + cmake_bindir="$cmake_destdir/bin" ;; + linux_x86) + cmake_bindir="$cmake_destdir/bin" ;; + esac +} +have_correct_cmake=0 +if [ -x "$tools_dir/cmake-$cmake_majminpat_ver/bin/cmake" ]; then + # shellcheck disable=SC2016 + have_correct_cmake_VER=$("$tools_dir/cmake-$cmake_majminpat_ver/bin/cmake" --version | $DKMLSYS_AWK 'NR==1{print $NF}') + if [ "$have_correct_cmake_VER" = "$cmake_majminpat_ver" ]; then + have_correct_cmake=1 + fi +fi +if [ $have_correct_cmake -eq 0 ]; then + download_cmake +fi +# Handle tarball +if [ -e "$tools_dir/dl/cmake.tar.gz" ] && [ -n "$cmake_base" ]; then + rm -rf "$tools_dir/cmake-$cmake_majminpat_ver" + install -d "$cmake_destdir" + tar xCfz "$cmake_destdir" "$tools_dir/dl/cmake.tar.gz" + rm -f "$tools_dir/dl/cmake.tar.gz" + set +f + if [ -e "$cmake_destdir/$cmake_base/CMake.app" ]; then + mv "$cmake_destdir/$cmake_base/CMake.app/Contents"/* "$cmake_destdir/" + else + mv "$cmake_destdir/$cmake_base"/* "$cmake_destdir/" + fi + set -f +fi +# Handle Python wheel +if [ -e "$tools_dir/dl/cmake.whl" ]; then + rm -rf "$tools_dir/cmake-$cmake_majminpat_ver" + cd "$tools_dir/dl" + rm -rf cmake/data + # Don't want cmake/data/{aclocal,bash-completion,emacs,vim} + unzip -q cmake.whl 'cmake/data/bin/**' + unzip -q cmake.whl 'cmake/data/doc/**' + # Don't want cmake/data/share/cmake-$cmake_majmin_ver/Help + unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'include/**' + unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'Modules/**' + unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'Templates/**' + rm -f cmake.whl + cd - + set +f + install -d "$cmake_destdir/share" "$cmake_destdir/doc" "$cmake_destdir/bin" + mv "$tools_dir/dl/cmake/data/bin"/* "$cmake_destdir/bin/" + rm -rf "$cmake_destdir/share/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/cmake" + mv "$tools_dir/dl/cmake/data/share/cmake-$cmake_majmin_ver" "$cmake_destdir/share/" + if [ -e "$tools_dir/dl/cmake/data/doc/cmake" ]; then # Windows wheel + mv "$tools_dir/dl/cmake/data/doc/cmake" "$cmake_destdir/doc/" + fi + if [ -e "$tools_dir/dl/cmake/data/doc/cmake-$cmake_majmin_ver" ]; then # Linux wheel + mv "$tools_dir/dl/cmake/data/doc/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/" + fi + set -f + # other dirs: aclocal bash-completion emacs vim + rm -rf "$tools_dir/dl/cmake/data/share" + # be pedantic. if we don't know about a directory, it may be important. so error + # if some directory is non-empty + rmdir "$tools_dir/dl/cmake/data/bin" "$tools_dir/dl/cmake/data/doc" + rmdir "$tools_dir/dl/cmake/data" +fi + +# Put tools in PATH +export_cmake_vars +if [ -n "$cmake_bindir" ] && [ -d "$cmake_bindir" ]; then + tools_bin_dir=$(cd "$cmake_bindir" && pwd) + export PATH="$tools_bin_dir:$PATH" +else + echo "This platform is not supported. No cmake 3.25+ download logic has been added" >&2 + exit 1 +fi + +# Validate +"$cmake_bindir/cmake" --version > /dev/null + +# --- Run finder script --- + +cd "$PROJ_DIR" +"$cmake_bindir/cmake" \ + -D CMAKE_GENERATOR=Ninja -D CMAKE_MAKE_PROGRAM="$NINJA_EXE" \ + -D "DKTOOL_WORKDIR:FILEPATH=$tools_dir/work" -D "DKTOOL_CMDLINE:STRING=$*" \ + -P cmake/FindDkToolScripts.cmake \ No newline at end of file diff --git a/dk.cmd b/dk.cmd new file mode 100755 index 0000000..5d413cc --- /dev/null +++ b/dk.cmd @@ -0,0 +1,146 @@ +@ECHO OFF +REM Recommendation: Place this file in source control. +REM Auto-generated by `./dk dksdk.project.new` of DkHelloWorld. + +REM The canonical way to run this script is: ./dk +REM That works in Powershell on Windows, and in Unix. Copy-and-paste works! + +SETLOCAL + +REM Coding guidelines +REM 1. Microsoft way of getting around PowerShell permissions: +REM https://github.com/microsoft/vcpkg/blob/71422c627264daedcbcd46f01f1ed0dcd8460f1b/bootstrap-vcpkg.bat +REM 2. Write goto downward please so code flow is top to bottom. + +SET DK_CMAKE_VER=3.25.3 +SET DK_NINJA_VER=1.11.1 +SET DK_BUILD_TYPE=Release +SET DK_SHARE=%LOCALAPPDATA%\Programs\DkSDK\dktool +SET DK_PROJ_DIR=%~dp0 + +REM -------------- CMAKE -------------- + +REM Find CMAKE.EXE +where.exe /q cmake.exe >NUL 2>NUL +IF %ERRORLEVEL% neq 0 ( + goto FindDownloadedCMake +) +FOR /F "tokens=* usebackq" %%F IN (`where.exe cmake.exe`) DO ( + SET "DK_CMAKE_EXE=%%F" +) + +REM Check if present at /cmake-VER/bin/cmake.exe +:FindDownloadedCMake +IF EXIST %DK_SHARE%\cmake-%DK_CMAKE_VER%-windows-x86_64\bin\cmake.exe ( + SET "DK_CMAKE_EXE=%DK_SHARE%\cmake-%DK_CMAKE_VER%-windows-x86_64\bin\cmake.exe" + GOTO ValidateCMake +) + +REM Download CMAKE.EXE +bitsadmin /transfer dktool-cmake /download /priority FOREGROUND ^ + "https://github.com/Kitware/CMake/releases/download/v%DK_CMAKE_VER%/cmake-%DK_CMAKE_VER%-windows-x86_64.zip" ^ + "%TEMP%\cmake-%DK_CMAKE_VER%-windows-x86_64.zip" +IF %ERRORLEVEL% equ 0 ( + GOTO UnzipCMakeZip +) +REM Try PowerShell 3+ instead +powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "Invoke-WebRequest https://github.com/Kitware/CMake/releases/download/v%DK_CMAKE_VER%/cmake-%DK_CMAKE_VER%-windows-x86_64.zip -OutFile '%TEMP%\cmake-%DK_CMAKE_VER%-windows-x86_64.zip'" +IF %ERRORLEVEL% neq 0 ( + echo. + echo.Could not download CMake %DK_CMAKE_VER%. Make sure that PowerShell is installed + echo.and has not been disabled by a corporate policy. + echo. + EXIT /b 1 +) + +REM Unzip CMAKE.EXE (use PowerShell; could download unzip.exe and sha256sum.exe as well in case corporate policy) +:UnzipCMakeZip +powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "Expand-Archive '%TEMP%\cmake-%DK_CMAKE_VER%-windows-x86_64.zip' -DestinationPath '%DK_SHARE%'" +IF %ERRORLEVEL% neq 0 ( + echo. + echo.Could not unzip CMake %DK_CMAKE_VER%. Make sure that PowerShell is installed + echo.and has not been disabled by a corporate policy. + echo. + EXIT /b 1 +) +SET "DK_CMAKE_EXE=%DK_SHARE%\cmake-%DK_CMAKE_VER%-windows-x86_64\bin\cmake.exe" + +REM Validate cmake.exe +:ValidateCMake +"%DK_CMAKE_EXE%" -version >NUL 2>NUL +if %ERRORLEVEL% neq 0 ( + echo. + echo.%DK_CMAKE_EXE% + echo.is not responding to the -version option. Make sure that + echo.CMake is installed correctly. + echo. + exit /b 1 +) + +REM -------------- NINJA -------------- + +REM Find NINJA.EXE +where.exe /q ninja.exe >NUL 2>NUL +IF %ERRORLEVEL% neq 0 ( + goto FindDownloadedNinja +) +FOR /F "tokens=* usebackq" %%F IN (`where.exe ninja.exe`) DO ( + SET "DK_NINJA_EXE=%%F" +) + +REM Check if present at /ninja-VER/bin/ninja.exe +:FindDownloadedNinja +IF EXIST %DK_SHARE%\ninja-%DK_NINJA_VER%-windows-x86_64\bin\ninja.exe ( + SET "DK_NINJA_EXE=%DK_SHARE%\ninja-%DK_NINJA_VER%-windows-x86_64\bin\ninja.exe" + GOTO ValidateNinja +) + +REM Download NINJA.EXE +bitsadmin /transfer dktool-ninja /download /priority FOREGROUND ^ + "https://github.com/ninja-build/ninja/releases/download/v%DK_NINJA_VER%/ninja-win.zip" ^ + "%TEMP%\ninja-%DK_NINJA_VER%-windows-x86_64.zip" +IF %ERRORLEVEL% equ 0 ( + GOTO UnzipNinjaZip +) +REM Try PowerShell 3+ instead +powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "Invoke-WebRequest https://github.com/ninja-build/ninja/releases/download/v%DK_NINJA_VER%/ninja-win.zip -OutFile '%TEMP%\ninja-%DK_NINJA_VER%-windows-x86_64.zip'" +IF %ERRORLEVEL% neq 0 ( + echo. + echo.Could not download Ninja %DK_NINJA_VER%. Make sure that PowerShell is installed + echo.and has not been disabled by a corporate policy. + echo. + EXIT /b 1 +) + +REM Unzip NINJA.EXE (use PowerShell; could download unzip.exe and sha256sum.exe as well in case corporate policy) +:UnzipNinjaZip +powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "Expand-Archive '%TEMP%\ninja-%DK_NINJA_VER%-windows-x86_64.zip' -DestinationPath '%DK_SHARE%\ninja-%DK_NINJA_VER%-windows-x86_64\bin'" +IF %ERRORLEVEL% neq 0 ( + echo. + echo.Could not unzip Ninja %DK_NINJA_VER%. Make sure that PowerShell is installed + echo.and has not been disabled by a corporate policy. + echo. + EXIT /b 1 +) +SET "DK_NINJA_EXE=%DK_SHARE%\ninja-%DK_NINJA_VER%-windows-x86_64\bin\ninja.exe" + +REM Validate ninja.exe +:ValidateNinja +"%DK_NINJA_EXE%" --version >NUL 2>NUL +if %ERRORLEVEL% neq 0 ( + echo. + echo.%DK_NINJA_EXE% + echo.is not responding to the --version option. Make sure that + echo.Ninja is installed correctly. + echo. + exit /b 1 +) + +REM -------------- Run finder -------------- + +cd %DK_PROJ_DIR% +"%DK_CMAKE_EXE%" -D CMAKE_GENERATOR=Ninja -D "CMAKE_MAKE_PROGRAM=%DK_NINJA_EXE%" -D "DKTOOL_WORKDIR:FILEPATH=%DK_SHARE%\work" -D "DKTOOL_CMDLINE:STRING=%*" -P cmake/FindDkToolScripts.cmake diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..9736cc9 --- /dev/null +++ b/environment.yml @@ -0,0 +1,7 @@ +name: c-capnproto +# channels: +# - conda-forge +# - defaults +dependencies: + - 'python>=3.8' + - meson diff --git a/gtest b/gtest deleted file mode 160000 index d225acc..0000000 --- a/gtest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d225acc90bc3a8c420a9bcd1f033033c1ccd7fe0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..f1516ba --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,12 @@ +include(FetchContent) +FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG f8d7d77c06936315286eb55f8de22cd23c188571 # v1.14.0 +) +FetchContent_MakeAvailable(googletest) + +include(GoogleTest) +add_executable(c-capnproto-testcases addressbook.capnp.c capn-stream-test.cpp capn-test.cpp example-test.cpp) +target_link_libraries(c-capnproto-testcases PRIVATE CapnC_Runtime GTest::gtest) + +gtest_add_tests(TARGET c-capnproto-testcases) diff --git a/tests/example-test.cpp b/tests/example-test.cpp index 10f0ff8..80e3922 100644 --- a/tests/example-test.cpp +++ b/tests/example-test.cpp @@ -85,7 +85,7 @@ TEST(Examples, RoundTripPerson) { { // Write serialized object to file system. - FILE *f = fopen("tests/example-test.cpp.Person.out", "wb"); + FILE *f = fopen("example-test.cpp.Person.out", "wb"); ASSERT_NE(f, (void*)0); fwrite(buf, 1 /* size */, sz /* count */, f); int close_ret = fclose(f);