diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100644 index 0000000..1ce2c7a --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,113 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: CMake on multiple platforms + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ${{ matrix.os }} + env: + BUILD_OUTPUT_DIR: ${{ github.workspace }}/build + + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + + # Set up a matrix to run the following 3 configurations: + # 1. + # 2. + # 3. + # + # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. + matrix: + os: [ubuntu-latest, windows-latest] + build_type: [Release] + c_compiler: [gcc, clang] + include: + - os: windows-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + - os: windows-latest + c_compiler: clang + + + steps: + - uses: actions/checkout@v3 + # Add Meson installation steps here + - name: Install Meson (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y meson + + - name: Install MinGW and Meson (Windows) + if: matrix.os == 'windows-latest' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + install: mingw-w64-x86_64-meson mingw-w64-x86_64-libgit2 mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja base-devel git mingw-w64-x86_64-cmake + upgrade: true + + + - name: Configure CMake (Windows) + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + if: matrix.os == 'windows-latest' + run: | + cmake -B $BUILD_OUTPUT_DIR -G"MSYS Makefiles" -S $BUILD_OUTPUT_DIR/.. + shell: msys2 {0} + + - name: Configure CMake (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: > + cmake -B $BUILD_OUTPUT_DIR + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + + + - name: Build (Windows) + if: matrix.os == 'windows-latest' + shell: msys2 {0} + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build $BUILD_OUTPUT_DIR --config ${{ matrix.build_type }} + + - name: Build (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: cmake --build $BUILD_OUTPUT_DIR --config ${{ matrix.build_type }} + + - name: Test (Ubuntu) + working-directory: ${{ env.BUILD_OUTPUT_DIR }} + if: matrix.os == 'ubuntu-latest' + run: | + ctest --build-config ${{ matrix.build_type }} --output-on-failure + if [ $? -ne 0 ]; then + cat Testing/Temporary/LastTest.log + exit 1 + fi + + - name: Test (Windows) + working-directory: ${{ env.BUILD_OUTPUT_DIR }} + if: matrix.os == 'windows-latest' + shell: msys2 {0} + run: | + export PATH="$BUILD_OUTPUT_DIR/Criterion/src:$BUILD_OUTPUT_DIR/Criterion/subprojects/nanomsg:$BUILD_OUTPUT_DIR/Criterion/subprojects/nanopb:$BUILD_OUTPUT_DIR/Criterion/subprojects/boxfort/src:$BUILD_OUTPUT_DIR/Criterion/subprojects/libgit2:$PATH" + ctest --build-config ${{ matrix.build_type }} --output-on-failure + if [ $? -ne 0 ]; then + cat Testing/Temporary/LastTest.log + exit 1 + fi \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e4fc3e..3bd13eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,8 +74,9 @@ else () message (FATAL_ERROR "No memory stream implementation found") endif () -include_directories (include src ${PROJECT_BINARY_DIR}/gen) add_library (fmem ${SOURCES}) +add_library (fmem::fmem ALIAS fmem) +target_include_directories (fmem PUBLIC include src "${PROJECT_BINARY_DIR}/gen") get_property (FMEM_LIBTYPE TARGET fmem @@ -115,13 +116,66 @@ install(TARGETS fmem ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES - fmem.h - ${PROJECT_BINARY_DIR}/gen/fmem-export.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + ${PROJECT_BINARY_DIR}/gen/fmem.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# Check if this is the main project and BUILD_TESTING was not already set by the user +if("${CMAKE_SOURCE_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}" AND NOT DEFINED BUILD_TESTING) + message(WARNING "Detected that we're only compiling this project. BUILD_TESTING was not explicitly set, defaulting to BUILD_TESTING=ON. To disable testing, set BUILD_TESTING=OFF.") +endif() include (CTest) - -if (BUILD_TESTING) - find_package (Criterion REQUIRED) - add_subdirectory (test) -endif () +if (WIN32) + set(LIB_EXT ".dll.a") +else() + set(LIB_EXT ".a") +endif() + +if ("${CMAKE_SOURCE_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}" AND BUILD_TESTING) + find_package(Criterion QUIET) + if (NOT CRITERION_FOUND) + find_program(MESON_FOUND meson) + + if(NOT MESON_FOUND) + message(STATUS "Meson not found. Attempting to call meson --version for debugging.") + execute_process( + COMMAND meson --version + RESULT_VARIABLE MESON_VERSION_RESULT + OUTPUT_VARIABLE MESON_VERSION_OUTPUT + ERROR_QUIET + ) + if(MESON_VERSION_RESULT EQUAL 0) + message(STATUS "Meson version: ${MESON_VERSION_OUTPUT}") + else() + message(WARNING "Meson not found or not callable from the shell.") + endif() +endif() + if (MESON_FOUND) + message(STATUS "Criterion not installed, cloning and building from source.") + + # Clone Criterion into the project root directory + if(NOT EXISTS "${PROJECT_SOURCE_DIR}/Criterion") + execute_process(COMMAND git clone --depth=1 https://github.com/Snaipe/Criterion.git "${PROJECT_SOURCE_DIR}/Criterion") + endif() + + # Set include directories and library paths + set(CRITERION_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/Criterion/include") + set(CRITERION_LIBRARIES "${CMAKE_BINARY_DIR}/Criterion/src/libcriterion${LIB_EXT}") + + # Check if criterion.h exists in the provided include directory + if(EXISTS "${CRITERION_INCLUDE_DIRS}/criterion/criterion.h") + message(STATUS "Found criterion.h in: ${CRITERION_INCLUDE_DIRS}/criterion") + else() + message(FATAL_ERROR "criterion.h not found in: ${CRITERION_INCLUDE_DIRS}/criterion") + endif() + # Build Criterion in a subdirectory within the main build directory + execute_process(COMMAND ${CMAKE_COMMAND} -E chdir "${PROJECT_SOURCE_DIR}/Criterion" meson "${CMAKE_BINARY_DIR}/Criterion") + execute_process(COMMAND ${CMAKE_COMMAND} -E chdir "${PROJECT_SOURCE_DIR}/Criterion" meson compile -C "${CMAKE_BINARY_DIR}/Criterion") + + else() + message(FATAL_ERROR "Meson build system not found. Unable to build Criterion from source.") + endif() + endif() + + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/include/fmem.h.in b/include/fmem.h.in index 4db7a4a..0c63dba 100644 --- a/include/fmem.h.in +++ b/include/fmem.h.in @@ -10,10 +10,14 @@ struct fmem_reserved { }; typedef struct fmem_reserved fmem; - +#ifdef __cplusplus +extern "C" { +#endif FMEM_API void fmem_init(fmem *file); FMEM_API void fmem_term(fmem *file); FMEM_API FILE *fmem_open(fmem *file, const char *mode); FMEM_API void fmem_mem(fmem *file, void **mem, size_t *size); - +#ifdef __cplusplus +} +#endif #endif /* !FMEM_H_ */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 519bf48..fa8c661 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,8 +1,52 @@ set (TEST_SOURCES tests.c) +if (WIN32) + set(LIB_EXT ".dll.a") +else() + set(LIB_EXT ".a") +endif() + +# Append additional libraries to CRITERION_LIBRARIES if they exist +if(EXISTS "${CMAKE_BINARY_DIR}/Criterion/subprojects/nanomsg/libnanomsg${LIB_EXT}") + list(APPEND CRITERION_LIBRARIES "${CMAKE_BINARY_DIR}/Criterion/subprojects/nanomsg/libnanomsg${LIB_EXT}") +endif() -include_directories (SYSTEM ${CRITERION_INCLUDE_DIRS}) +if(EXISTS "${CMAKE_BINARY_DIR}/Criterion/subprojects/nanopb/libprotobuf_nanopb_static${LIB_EXT}") + list(APPEND CRITERION_LIBRARIES "${CMAKE_BINARY_DIR}/Criterion/subprojects/nanopb/libprotobuf_nanopb_static${LIB_EXT}") +endif() -add_executable (unit_tests ${TEST_SOURCES}) -target_link_libraries (unit_tests fmem ${CRITERION_LIBRARIES}) +if(EXISTS "${CMAKE_BINARY_DIR}/Criterion/subprojects/boxfort/src/libboxfort${LIB_EXT}") + list(APPEND CRITERION_LIBRARIES "${CMAKE_BINARY_DIR}/Criterion/subprojects/boxfort/src/libboxfort${LIB_EXT}") +endif() + +if(EXISTS "${CMAKE_BINARY_DIR}/Criterion/subprojects/libgit2/libgit2${LIB_EXT}") + list(APPEND CRITERION_LIBRARIES "${CMAKE_BINARY_DIR}/Criterion/subprojects/libgit2/libgit2${LIB_EXT}") +else() + # Execute the find program to locate libgit2.a don't write libgit2${LIB_EXT} because FIND: Parameter format not correct + execute_process( + COMMAND find "${CMAKE_BINARY_DIR}/Criterion" -name libgit2${LIB_EXT} + OUTPUT_VARIABLE FOUND_LIBGIT2 + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # If found, append to CRITERION_LIBRARIES + if(FOUND_LIBGIT2) + message(STATUS "Found libgit2.a at: ${FOUND_LIBGIT2}") + list(APPEND CRITERION_LIBRARIES "${FOUND_LIBGIT2}") + else() + message(WARNING "libgit2.a not found in Criterion subprojects.") + endif() +endif() + + +include_directories(SYSTEM "${CRITERION_INCLUDE_DIRS}") + +# Add a debug message for test sources +message(STATUS "Adding executable for unit_tests with sources: ${TEST_SOURCES}") + +add_executable (unit_tests "${TEST_SOURCES}") +# Add a debug message +message(STATUS "Linking unit_tests with libraries: fmem, ${CRITERION_LIBRARIES}") + +target_link_libraries (unit_tests fmem "${CRITERION_LIBRARIES}") add_test (unit_tests unit_tests)