From bce2132aa5174bed9f17b0e938e3b7799fa28c7c Mon Sep 17 00:00:00 2001 From: "Lars T. Kyllingstad" Date: Mon, 19 Feb 2024 13:33:33 +0100 Subject: [PATCH] Upgrade to Conan 2 (#747) * Upgrade to Conan 2 This fixes issue #718 (and incidentally fixes #702 too). The modified `` imports and various changes from `int` to `std::size_t` are a consequence of using a newer version of MS GSL. I changed the dependency version so we can use an upstream CMake package configuration file which is compatible with the one generated by Conan 2's `CMakeDeps` generator. This should enable us to use the same `find_package()` commands and target names regardless of whether the build is running under Conan or not. This also removes the ability to run Conan from within CMake, because upstream hasn't released a version of the cmake-conan helper script with full support for all Conan 2 features yet. (Notably, support for the `CMakeToolchain` generator is missing.) * Update GH Actions workflows for Conan 2 * Use a conanio Docker image that has Conan 2 * Run pure-CMake CI build in Docker, drop Windows * Fix minor mistake in workflow file * Fix more small mistakes in CI * More legible build matrix elements in non-Conan CI * Ensure that libdl is listed as a dependency of fmilib::shared * Also import proxyfmu executable to the build directory * Update version numbers in README * Clean up GitHub Actions workflows a bit * Set the cpp_info property `cmake_target_name` as `libcosim::cosim` in the `package_info` method. This is because otherwise CMakeDeps incorrectly generates the dependency in the target cmake file as `libcosim::libcosim`. (i.e. -Target-release.cmake, see https://docs.conan.io/2/reference/tools/cmake/cmakedeps.html#generated-files). This would not be found via `find_package(libcosim REQUIRED)`. * Uploading artifacts to jfrog (#751) gcc9 builds are not available from conancenter. Built libraries are uploaded to osp jfrog. * Updated proxyfmu * Updated version.txt to 0.10.3 --------- Co-authored-by: David Heejong Park Co-authored-by: David Heejong Park <88651540+davidhjp01@users.noreply.github.com> --- .github/workflows/ci-cmake.yml | 142 +++++------------ .github/workflows/ci-conan.yml | 57 ++++--- .gitignore | 2 + CHANGELOG.md | 7 + CMakeLists.txt | 55 +------ README.md | 8 +- cmake/FindFMILibrary.cmake | 1 + cmake/FindLIBZIP.cmake | 110 -------------- cmake/FindMS_GSL.cmake | 17 --- cmake/FindYAML_CPP.cmake | 36 ----- cmake/project-config.cmake.in | 13 +- conanfile.py | 160 ++++++++++++-------- src/CMakeLists.txt | 10 +- src/cosim/fmi/importer.cpp | 2 +- src/cosim/fmi/v1/fmu.cpp | 10 +- src/cosim/fmi/v2/fmu.cpp | 10 +- src/cosim/observer/slave_value_provider.cpp | 2 +- src/cosim/observer/time_series_observer.cpp | 6 +- tests/mock_slave.hpp | 16 +- version.txt | 2 +- 20 files changed, 223 insertions(+), 443 deletions(-) delete mode 100644 cmake/FindLIBZIP.cmake delete mode 100644 cmake/FindMS_GSL.cmake delete mode 100644 cmake/FindYAML_CPP.cmake diff --git a/.github/workflows/ci-cmake.yml b/.github/workflows/ci-cmake.yml index 32c6cf83d..acb474bf8 100644 --- a/.github/workflows/ci-cmake.yml +++ b/.github/workflows/ci-cmake.yml @@ -1,116 +1,56 @@ -name: libcosim CI CMake +name: CI without Conan # This workflow is triggered on pushes to the repository. on: [push] -env: - CONAN_LOGIN_USERNAME_OSP: ${{ secrets.osp_artifactory_usr }} - CONAN_PASSWORD_OSP: ${{ secrets.osp_artifactory_pwd }} - CONAN_REVISIONS_ENABLED: 1 - CONAN_NON_INTERACTIVE: 1 - jobs: - cmake-on-linux: - name: CMake - runs-on: ${{ matrix.os }} - env: - CC: gcc-${{ matrix.compiler_version }} - CXX: g++-${{ matrix.compiler_version }} + linux: + name: Linux + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - os: [ubuntu-20.04] build_type: [Debug, Release] - compiler_version: [9] - shared_libs: [ON, OFF] + shared_libs: [SHARED_LIBS=ON, SHARED_LIBS=OFF] timeout-minutes: 35 steps: - - uses: actions/checkout@v3 - - name: Install prerequisites - run: | - sudo apt-get install -y --no-install-recommends \ - doxygen \ - libboost-all-dev \ - libmsgsl-dev \ - libyaml-cpp-dev \ - libxerces-c-dev \ - libzip-dev - wget \ + - uses: actions/checkout@v4 + - name: Generate Dockerfile + run: | + mkdir /tmp/osp-builder-docker + cat </tmp/osp-builder-docker/Dockerfile + FROM debian:bookworm + RUN apt-get update && apt-get install -y --no-install-recommends \ + cmake \ + build-essential \ + doxygen \ + wget \ + libboost-all-dev \ + libmsgsl-dev \ + libyaml-cpp-dev \ + libxerces-c-dev \ + libzip-dev zipcmp zipmerge ziptool + RUN wget \ + --no-check-certificate \ "https://github.com/viproma/debian-fmilib/releases/download/debian%2F2.0.3-1/libfmilib2_2.0.3-1_amd64.deb" \ "https://github.com/viproma/debian-fmilib/releases/download/debian%2F2.0.3-1/libfmilib2-dev_2.0.3-1_amd64.deb" - sudo dpkg -i libfmilib2_2.0.3-1_amd64.deb libfmilib2-dev_2.0.3-1_amd64.deb - - name: CMake - configure - run: | - cmake \ - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ - -DCMAKE_PREFIX_PATH=fmilibrary \ - -DCMAKE_INSTALL_PREFIX=install \ - -DBUILD_SHARED_LIBS=${{ matrix.shared_libs }} \ - -B build - - name: CMake - build - run: cmake --build build - - name: CMake - build doc - run: cmake --build build --target doc - - name: CMake - test - run: | + RUN dpkg -i libfmilib2_2.0.3-1_amd64.deb libfmilib2-dev_2.0.3-1_amd64.deb + COPY entrypoint.sh / + ENTRYPOINT /entrypoint.sh + EOF + - name: Generate entrypoint.sh + run: | + cat <<'EOF' >/tmp/osp-builder-docker/entrypoint.sh + #!/bin/bash + mkdir build cd build - ctest - - name: CMake - install - run: | - cmake --build build --target install - cmake --build build --target install-doc - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: libcosim-${{ runner.os }}-${{ matrix.build_type }}-gcc${{ matrix.compiler_version }} - path: install - - - cmake-on-windows: - name: CMake - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [windows-2019] - build_type: [Debug, Release] - shared: ["True", "False"] - timeout-minutes: 35 - - steps: - - uses: actions/checkout@v3 - - name: Install prerequisites - run: | - pip3 install --upgrade setuptools pip - pip3 install conan==1.59 - choco install doxygen.install - conan remote add osp https://osp.jfrog.io/artifactory/api/conan/conan-local --force - conan install . -s build_type=${{ matrix.build_type }} -o shared=${{ matrix.shared }} -g deploy - - name: CMake - configure - shell: bash - run: | - cmake . \ - -A x64 \ - -DCMAKE_PREFIX_PATH="ms-gsl;boost;fmilibrary;libzip;xerces-c;yaml-cpp;bzip2;zlib;xz_utils" \ - -DCMAKE_INSTALL_PREFIX=install \ - -DBUILD_SHARED_LIBS=${{ matrix.shared }} \ - -B build - - name: CMake - build - run: cmake --build build --config ${{ matrix.build_type }} - - name: CMake - build doc - run: cmake --build build --config ${{ matrix.build_type }} --target doc - - name: CMake - test - run: | - .\activate_run.ps1 - cd build - ctest -C ${{ matrix.build_type }} - - name: CMake - install - run: | - cmake --build build --config ${{ matrix.build_type }} --target install - cmake --build build --config ${{ matrix.build_type }} --target install-doc - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: libcosim-${{ runner.os }}-${{ matrix.build_type }} - path: install + cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_${{ matrix.shared_libs }} /mnt/source + cmake --build . + ctest --output-on-failure + EOF + chmod 0755 /tmp/osp-builder-docker/entrypoint.sh + - name: Build Docker image + run: docker build -t osp-builder /tmp/osp-builder-docker/ + - name: Build cosim + run: docker run --rm -v $(pwd):/mnt/source:ro osp-builder diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 0d4e568ff..b2258221c 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -1,34 +1,30 @@ -name: libcosim CI Conan +name: CI with Conan # This workflow is triggered on pushes to the repository. on: [push, workflow_dispatch] jobs: - conan-on-linux: - name: Conan + linux: + name: Linux runs-on: ubuntu-latest strategy: fail-fast: false matrix: build_type: [Debug, Release] compiler_version: [9] - compiler_libcxx: [libstdc++11] option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] option_shared: ['shared=True', 'shared=False'] timeout-minutes: 35 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Generate Dockerfile run: | mkdir /tmp/osp-builder-docker cat <<'EOF' >/tmp/osp-builder-docker/Dockerfile - FROM conanio/gcc${{ matrix.compiler_version }} + FROM conanio/gcc${{ matrix.compiler_version }}-ubuntu16.04 ENV CONAN_LOGIN_USERNAME_OSP=${{ secrets.osp_artifactory_usr }} ENV CONAN_PASSWORD_OSP=${{ secrets.osp_artifactory_pwd }} - ENV CONAN_REVISIONS_ENABLED=1 - ENV CONAN_NON_INTERACTIVE=1 - ENV CONAN_USE_ALWAYS_SHORT_PATHS=1 ENV LIBCOSIM_RUN_TESTS_ON_CONAN_BUILD=1 COPY entrypoint.sh / ENTRYPOINT /entrypoint.sh @@ -48,28 +44,30 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -s compiler.libcxx=${{ matrix.compiler_libcxx }} -o ${{ matrix.option_proxyfmu }} -o ${{ matrix.option_shared }} -b missing . osp/${CHANNEL} - conan upload --all -c -r osp '*' + conan create \ + --settings="build_type=${{ matrix.build_type }}" \ + --options="${{ matrix.option_proxyfmu }}" \ + --options="${{ matrix.option_shared }}" \ + --build=missing \ + --user=osp \ + --channel="${CHANNEL}" \ + . + conan upload --confirm --remote=osp '*' EOF chmod 0755 /tmp/osp-builder-docker/entrypoint.sh - name: Build Docker image - run: | - docker build -t osp-builder /tmp/osp-builder-docker/ + run: docker build -t osp-builder /tmp/osp-builder-docker/ - name: Build cosim run: | docker run --rm --env GITHUB_REF="$GITHUB_REF" -v $(pwd):/mnt/source:ro osp-builder - conan-on-windows: - name: Conan + windows: + name: Windows runs-on: ${{ matrix.os }} env: CONAN_LOGIN_USERNAME_OSP: ${{ secrets.osp_artifactory_usr }} CONAN_PASSWORD_OSP: ${{ secrets.osp_artifactory_pwd }} - CONAN_REVISIONS_ENABLED: 1 - CONAN_NON_INTERACTIVE: 1 - CONAN_USE_ALWAYS_SHORT_PATHS: 1 - CONAN_USER_HOME_SHORT: C:\c LIBCOSIM_RUN_TESTS_ON_CONAN_BUILD: 1 strategy: fail-fast: false @@ -78,16 +76,18 @@ jobs: build_type: [Debug, Release] option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] option_shared: ['shared=True', 'shared=False'] - timeout-minutes: 35 + timeout-minutes: 120 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install prerequisites run: | pip3 install --upgrade setuptools pip - pip3 install conan==1.59 + pip3 install conan - name: Configure Conan - run: conan remote add osp https://osp.jfrog.io/artifactory/api/conan/conan-local --force + run: | + conan profile detect + conan remote add osp https://osp.jfrog.io/artifactory/api/conan/conan-local --force - name: Conan create shell: bash run: | @@ -99,6 +99,13 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -o ${{ matrix.option_proxyfmu }} -o ${{ matrix.option_shared }} -b missing . osp/${CHANNEL} + conan create \ + --settings="build_type=${{ matrix.build_type }}" \ + --options="${{ matrix.option_proxyfmu }}" \ + --options="${{ matrix.option_shared }}" \ + --build=missing \ + --user=osp \ + --channel="${CHANNEL}" \ + . - name: Conan upload - run: conan upload --all -c -r osp '*' + run: conan upload --confirm --remote=osp '*' diff --git a/.gitignore b/.gitignore index 4459ca29f..aadaf1b1d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ cmake-build-*/ # Visual Studio Code .vscode/ + +CMakeUserPresets.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a9aa3eb6b..1060c3069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to libcosim will be documented in this file. This includes n This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) +### [v0.10.3] - 2024-02-19 +##### Fixed +* parseURI null check and error handling implemented. +##### Changed +* Upgraded Conan to v2 + ### [v0.10.2] - 2023-02-08 ##### Fixed * Update to proxyfmu 0.3.1 due to a disconnection issue related to Thrift. @@ -217,3 +223,4 @@ First OSP JIP partner release [v0.10.0]: https://github.com/open-simulation-platform/cse-core/compare/v0.9.0...v0.10.0 [v0.10.1]: https://github.com/open-simulation-platform/cse-core/compare/v0.10.0...v0.10.1 [v0.10.2]: https://github.com/open-simulation-platform/cse-core/compare/v0.10.1...v0.10.2 +[v0.10.3]: https://github.com/open-simulation-platform/cse-core/compare/v0.10.2...v0.10.3 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 99da9ff02..1b1644fb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.19) file(STRINGS "${CMAKE_SOURCE_DIR}/version.txt" projectVersion) project("libcosim" VERSION ${projectVersion}) message("Current libcosim version: ${CMAKE_PROJECT_VERSION}\n") @@ -13,8 +13,6 @@ option(LIBCOSIM_BUILD_TESTS "Build test suite" ON) option(LIBCOSIM_BUILD_APIDOC "Build API documentation (requires Doxygen)" ON) option(LIBCOSIM_BUILD_PRIVATE_APIDOC "Build private API documentation (only used if LIBCOSIM_BUILD_APIDOC=ON)" OFF) option(LIBCOSIM_STANDALONE_INSTALLATION "Whether to build for a standalone installation (Linux only; sets a relative RPATH)" OFF) -option(LIBCOSIM_USING_CONAN "Whether Conan is used for package management" OFF) -option(LIBCOSIM_USING_CONAN_AUTO_CONFIG "Whether Conan should be configured automatically by CMake" OFF) option(LIBCOSIM_WITH_PROXYFMU "Whether or not to build with proxy-fmu integration" OFF) option(LIBCOSIM_NO_FMI_LOGGING "Disable FMI logging during simulation" OFF) @@ -98,44 +96,6 @@ set(LIBCOSIM_EXPORT_TARGET "${PROJECT_NAME}-targets") # Dependencies # ============================================================================== -if(LIBCOSIM_USING_CONAN) - if(NOT LIBCOSIM_USING_CONAN_AUTO_CONFIG OR CONAN_EXPORTED) - # Opting for manual invocation of conan install prior to loading CMake - # or conan create has been invoked, setting CONAN_EXPORTED. - if(EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) - include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) - conan_basic_setup(NO_OUTPUT_DIRS) - else() - message(FATAL_ERROR "The file conanbuildinfo.cmake doesn't exist, you have to run conan install first") - endif() - else() - # Auto config specified and conan create is not running. - # We'll let CMake run the conan commands for us. - - # This is where the magic happens. - # The file has been modified to search for the conan executable on linux systems. - include(cmake/conan.cmake) - conan_cmake_autodetect(settings) - - set(proxyfmu_option False) - if(LIBCOSIM_WITH_PROXYFMU) - set(proxyfmu_option True) - endif() - - # Force add osp remote - conan_add_remote(NAME osp URL https://osp.jfrog.io/artifactory/api/conan/conan-local) - - # Run conan install with auto-detected settings and -b missing flag - # and -o proxyfmu=True if LIBCOSIM_WITH_PROXYFMU=ON - conan_cmake_run( - CONANFILE conanfile.py - OPTIONS proxyfmu=${proxyfmu_option} - BUILD missing - SETTINGS ${settings} - BASIC_SETUP NO_OUTPUT_DIRS) - endif() -endif() - set(Boost_components date_time log) if (LIBCOSIM_BUILD_TESTS) list(APPEND Boost_components timer unit_test_framework) @@ -148,11 +108,11 @@ find_package(Boost REQUIRED COMPONENTS ${Boost_components}) if(BUILD_SHARED_LIBS AND NOT DEFINED FMILibrary_USE_SHARED_LIB) set(FMILibrary_USE_SHARED_LIB TRUE) endif() -find_package(FMILibrary REQUIRED) -find_package(LIBZIP REQUIRED) -find_package(MS_GSL REQUIRED) -find_package(YAML_CPP REQUIRED) -find_package(XercesC REQUIRED) +find_package(FMILibrary MODULE REQUIRED) +find_package(libzip REQUIRED) +find_package(Microsoft.GSL REQUIRED) +find_package(yaml-cpp REQUIRED) +find_package(XercesC MODULE REQUIRED) if(LIBCOSIM_WITH_PROXYFMU) find_package(PROXYFMU CONFIG REQUIRED) endif() @@ -244,9 +204,6 @@ install(FILES "${versionFile}" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}") # Install custom find modules install(FILES "${CMAKE_SOURCE_DIR}/cmake/FindFMILibrary.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindLIBZIP.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindMS_GSL.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindYAML_CPP.cmake" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}" ) diff --git a/README.md b/README.md index beb5dfcdd..9955e3fc3 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ in the section below or you can use conan. As libcosim is made available as a conan package on https://osp.jfrog.io, you can include it in your application following these steps: -* Install [Conan] version 1.x +* Install [Conan] version 2.x * Add the OSP Conan repository as a remote: conan remote add osp https://osp.jfrog.io/artifactory/api/conan/conan-local @@ -35,10 +35,10 @@ How to build ### Required tools - * Compilers: [Visual Studio] >= 16.0/2019 (Windows), GCC >= 7 (Linux) - * Build tool: [CMake] + * Compilers: [Visual Studio] >= 16.0/2019 (Windows), GCC >= 9 (Linux) + * Build tool: [CMake] >= 3.19 * API documentation generator (optional): [Doxygen] - * Package manager (optional): [Conan] 1.x + * Package manager (optional): [Conan] 2.x Throughout this guide, we will use Conan to manage dependencies. However, it should be possible to use other package managers as well, such as [vcpkg], and diff --git a/cmake/FindFMILibrary.cmake b/cmake/FindFMILibrary.cmake index 530e7572d..71bbb0179 100644 --- a/cmake/FindFMILibrary.cmake +++ b/cmake/FindFMILibrary.cmake @@ -112,6 +112,7 @@ if (FMILibrary_SHARED_LIBRARY) add_library ("fmilib::shared" SHARED IMPORTED) set_target_properties ("fmilib::shared" PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_DL_LIBS}" INTERFACE_INCLUDE_DIRECTORIES "${FMILibrary_INCLUDE_DIRS}") if (WIN32) set_target_properties ("fmilib::shared" PROPERTIES diff --git a/cmake/FindLIBZIP.cmake b/cmake/FindLIBZIP.cmake deleted file mode 100644 index d079825ef..000000000 --- a/cmake/FindLIBZIP.cmake +++ /dev/null @@ -1,110 +0,0 @@ -# - CMake script for locating libzip -# -# If the script succeeds, it will create an IMPORTED target named -# "libzip::libzip", plus set the following variables: -# -# LIBZIP_FOUND - If the library was found -# LIBZIP_INCLUDE_DIRS - The directory that contains the header files. -# LIBZIP_LIBRARIES - Contains "libzip::libzip" -# LIBZIP_LIBRARY - Path to static/import library file. -# -cmake_minimum_required (VERSION 3.0.0) - -find_package(BZip2 QUIET) # optional package - used when building using conan -find_package(OpenSSL COMPONENTS Crypto SSL QUIET) # optional package - used when building using conan on linux -find_package(ZLIB QUIET) # optional package - used when building using conan -find_package(LibLZMA QUIET) # optional package - used when building using conan - -# Find static library, and use its path prefix to provide a HINTS option to the -# other find_*() commands. -find_library (LIBZIP_LIBRARY "zip" - PATHS ${LIBZIP_DIR} $ENV{LIBZIP_DIR} - PATH_SUFFIXES "lib") -mark_as_advanced (LIBZIP_LIBRARY) -unset (_LIBZIP_hints) -if (LIBZIP_LIBRARY) - get_filename_component (_LIBZIP_prefix "${LIBZIP_LIBRARY}" PATH) - get_filename_component (_LIBZIP_prefix "${_LIBZIP_prefix}" PATH) - set (_LIBZIP_hints "HINTS" "${_LIBZIP_prefix}") - unset (_LIBZIP_prefix) -endif () - -# Find header files and, on Windows, the DLL -find_path (LIBZIP_INCLUDE_DIR_zip "zip.h" - ${_LIBZIP_hints} - PATHS ${LIBZIP_DIR} $ENV{LIBZIP_DIR} - PATH_SUFFIXES "include") -find_path (LIBZIP_INCLUDE_DIR_zipconf "zipconf.h" - ${_LIBZIP_hints} - PATHS ${LIBZIP_DIR} $ENV{LIBZIP_DIR} - PATH_SUFFIXES "include" "lib/libzip/include") -set (LIBZIP_INCLUDE_DIRS - "${LIBZIP_INCLUDE_DIR_zip}" "${LIBZIP_INCLUDE_DIR_zipconf}" -) - -mark_as_advanced (LIBZIP_INCLUDE_DIRS) - -if (WIN32) - find_file (LIBZIP_DLL NAMES "zip.dll" "libzip.dll" - ${_LIBZIP_hints} - PATHS ${LIBZIP_DIR} $ENV{LIBZIP_DIR} - PATH_SUFFIXES "bin" "lib" - NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - mark_as_advanced (LIBZIP_DLL) -endif () -unset (_LIBZIP_hints) - -# Create the IMPORTED targets. -if (LIBZIP_LIBRARY) - add_library ("libzip::libzip" SHARED IMPORTED) - set_target_properties ("libzip::libzip" PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${LIBZIP_LIBRARY}" - INTERFACE_COMPILE_DEFINITIONS "LIBZIP_STATIC_LIB_ONLY" - INTERFACE_INCLUDE_DIRECTORIES "${LIBZIP_INCLUDE_DIRS}") - if (WIN32) - set_target_properties ("libzip::libzip" PROPERTIES - IMPORTED_IMPLIB "${LIBZIP_LIBRARY}" - IMPORTED_LOCATION "${LIBZIP_DLL}") - else () # not WIN32 - set_target_properties ("libzip::libzip" PROPERTIES - IMPORTED_LOCATION "${LIBZIP_LIBRARY}") - endif () - - set (LIBZIP_LIBRARIES "libzip::libzip") - - ##### required by conan when linking libzip statically #### - set(LIBZIP_interfaceLinkLibraries) - if (ZLIB_FOUND) - list(APPEND LIBZIP_interfaceLinkLibraries ZLIB::ZLIB) - endif() - if (LIBLZMA_FOUND) - list(APPEND LIBZIP_interfaceLinkLibraries LibLZMA::LibLZMA) - endif() - if (BZip2_FOUND) - list(APPEND LIBZIP_interfaceLinkLibraries BZip2::BZip2) - endif() - if (OpenSSL_FOUND) - list(APPEND LIBZIP_interfaceLinkLibraries OpenSSL::SSL OpenSSL::Crypto) - endif() - if (BZip2_FOUND OR OpenSSL_FOUND) - set_property(TARGET libzip::libzip - APPEND - PROPERTY INTERFACE_LINK_LIBRARIES - ${LIBZIP_interfaceLinkLibraries}) - endif() - ############################################################### -endif () - -# Debug print-out. -if (LIBZIP_PRINT_VARS) - message ("LIBZIP find script variables:") - message (" LIBZIP_INCLUDE_DIRS = ${LIBZIP_INCLUDE_DIRS}") - message (" LIBZIP_LIBRARIES = ${LIBZIP_LIBRARIES}") - message (" LIBZIP_DLL = ${LIBZIP_DLL}") - message (" LIBZIP_LIBRARY = ${LIBZIP_LIBRARY}") -endif () - -# Standard find_package stuff. -include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (LIBZIP DEFAULT_MSG LIBZIP_LIBRARIES LIBZIP_INCLUDE_DIRS) diff --git a/cmake/FindMS_GSL.cmake b/cmake/FindMS_GSL.cmake deleted file mode 100644 index 2e4049da0..000000000 --- a/cmake/FindMS_GSL.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# Finds the core guidelines support library. -# -# If found, the following is defined: -# - `MS_GSL_FOUND` and `MS_GSL_INCLUDE_DIRS` variables. -# - `gsl` target - -find_path(MS_GSL_INCLUDE_DIR "gsl/gsl") -if(MS_GSL_INCLUDE_DIR) - set(MS_GSL_INCLUDE_DIRS "${MS_GSL_INCLUDE_DIR}") - add_library(gsl INTERFACE IMPORTED) - set_target_properties(gsl PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${MS_GSL_INCLUDE_DIR}" - ) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args("MS_GSL" DEFAULT_MSG "MS_GSL_INCLUDE_DIRS") diff --git a/cmake/FindYAML_CPP.cmake b/cmake/FindYAML_CPP.cmake deleted file mode 100644 index 578fee2fb..000000000 --- a/cmake/FindYAML_CPP.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# Find yaml-cpp -# -# Find the native yaml-cpp headers and libraries. -# -# YAML_CPP_INCLUDE_DIRS - where to find yaml-cpp/yaml.h -# YAML_CPP_LIBRARIES - List of libraries when using yaml-cpp. -# YAML_CPP_FOUND - True if yaml-cpp found. -# - -find_path(YAML_CPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h) -mark_as_advanced(YAML_CPP_INCLUDE_DIR) - -find_library(YAML_CPP_LIBRARY NAMES yaml-cpp libyaml-cpp yaml-cppd yaml-cppmd libyaml-cppmd libyaml-cppmdd) -mark_as_advanced(YAML_CPP_LIBRARY) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAML_CPP - REQUIRED_VARS YAML_CPP_LIBRARY YAML_CPP_INCLUDE_DIR) - -if (YAML_CPP_FOUND) - - set(YAML_CPP_INCLUDE_DIRS ${YAML_CPP_INCLUDE_DIR}) - - if (NOT YAML_CPP_LIBRARIES) - set(YAML_CPP_LIBRARIES ${YAML_CPP_LIBRARY}) - endif() - - if (NOT TARGET yaml-cpp) - add_library(yaml-cpp UNKNOWN IMPORTED) - set_target_properties(yaml-cpp PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${YAML_CPP_INCLUDE_DIR}") - set_property(TARGET yaml-cpp APPEND PROPERTY - IMPORTED_LOCATION "${YAML_CPP_LIBRARY}") - endif() - -endif() diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in index daaa699a6..2752fc2c8 100644 --- a/cmake/project-config.cmake.in +++ b/cmake/project-config.cmake.in @@ -1,20 +1,17 @@ @PACKAGE_INIT@ + include ("@PACKAGE_targetsFile@") include(CMakeFindDependencyMacro) - list(APPEND CMAKE_MODULE_PATH "${PACKAGE_PREFIX_DIR}/@LIBCOSIM_CMAKE_INSTALL_DIR@") - -find_dependency(MS_GSL REQUIRED) find_dependency(Boost REQUIRED COMPONENTS date_time log) set(FMILibrary_USE_SHARED_LIB @FMILibrary_USE_SHARED_LIB@) -find_dependency(FMILibrary REQUIRED) -find_dependency(LIBZIP REQUIRED) -find_dependency(YAML_CPP REQUIRED) +find_dependency(FMILibrary MODULE REQUIRED) +find_dependency(libzip REQUIRED) +find_dependency(Microsoft.GSL REQUIRED) +find_dependency(yaml-cpp REQUIRED) find_dependency(XercesC REQUIRED) - if(@LIBCOSIM_WITH_PROXYFMU@) find_dependency(PROXYFMU CONFIG REQUIRED) endif() - list(REMOVE_AT CMAKE_MODULE_PATH -1) diff --git a/conanfile.py b/conanfile.py index b79504356..0daf54e8f 100755 --- a/conanfile.py +++ b/conanfile.py @@ -1,91 +1,121 @@ import os -from conans import ConanFile, CMake, RunEnvironment, tools -from os import path +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.cmake import CMakeToolchain, CMake, CMakeDeps, cmake_layout +from conan.tools.env import VirtualRunEnv +from conan.tools.files import copy, load class LibcosimConan(ConanFile): + # Basic package info name = "libcosim" + def set_version(self): + self.version = load(self, os.path.join(self.recipe_folder, "version.txt")).strip() + + # Metadata + license = "MPL-2.0" author = "osp" - exports = "version.txt" - scm = { - "type": "git", - "url": "auto", - "revision": "auto" - } - settings = "os", "compiler", "build_type", "arch" - generators = "cmake", "virtualrunenv" - requires = ( - "boost/1.71.0", - "fmilibrary/2.3", - "ms-gsl/2.1.0", - "libzip/1.7.3", - "yaml-cpp/0.7.0", - "xerces-c/3.2.2", - # conflict resolution - "openssl/1.1.1k", - "xz_utils/5.2.5", - "zlib/1.2.12" - ) + url = "https://github.com/open-simulation-platform/libcosim.git" + description = "A co-simulation library for C++" + # Binary configuration + package_type = "library" + settings = "os", "compiler", "build_type", "arch" options = { "shared": [True, False], + "fPIC": [True, False], "proxyfmu": [True, False], - "no_fmi_logging": [True, False]} - default_options = ( - "proxyfmu=False", - "shared=True", - "no_fmi_logging=False" - ) - - def is_tests_enabled(self): - return os.getenv("LIBCOSIM_RUN_TESTS_ON_CONAN_BUILD", "False").lower() in ("true", "1") + "no_fmi_logging": [True, False], + } + default_options = { + "shared": True, + "fPIC": True, + "proxyfmu": False, + "no_fmi_logging": False, + } - def set_version(self): - self.version = tools.load(path.join(self.recipe_folder, "version.txt")).strip() + # Dependencies/requirements + def requirements(self): + self.tool_requires("cmake/[>=3.19]") + self.requires("fmilibrary/[~2.3]") + self.requires("libzip/[>=1.7 <1.10]") # 1.10 deprecates some functions we use + self.requires("ms-gsl/[>=3 <5]", transitive_headers=True) + if self.options.proxyfmu: + self.requires("proxyfmu/0.3.2@osp/stable") + self.requires("boost/[~1.81]", transitive_headers=True) # Required by Thrift + else: + self.requires("boost/[>=1.71]", transitive_headers=True) + self.requires("yaml-cpp/[~0.8]") + self.requires("xerces-c/[~3.2]") + + # Exports + exports = "version.txt" + exports_sources = "*" + + # Build steps + + def layout(self): + cmake_layout(self) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC def configure(self): - self.options["boost"].shared = self.options.shared - self.options["fmilibrary"].shared = self.options.shared - self.options["libzip"].shared = self.options.shared - self.options["yaml-cpp"].shared = self.options.shared - self.options["xerces-c"].shared = self.options.shared + if self.options.shared: + self.options.rm_safe("fPIC") + self.options["*"].shared = self.options.shared - def requirements(self): - if self.options.proxyfmu: - self.requires("proxyfmu/0.3.1@osp/stable") + def generate(self): + # Copy dependencies to the folder where executables (tests, mainly) + # will be placed, so it's easier to run them. + bindir = os.path.join( + self.build_folder, + "output", + str(self.settings.build_type).lower(), + "bin") + for dep in self.dependencies.values(): + for depdir in dep.cpp_info.bindirs: + copy(self, "*.dll", depdir, bindir, keep_path=False) + copy(self, "*.pdb", depdir, bindir, keep_path=False) + copy(self, "proxyfmu*", depdir, bindir, keep_path=False) - def imports(self): - binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") - self.copy("proxyfmu*", dst=binDir, src="bin", keep_path=False) - self.copy("proxyfmu*", dst="tests", src="bin", keep_path=False) - self.copy("*.dll", dst=binDir, keep_path=False) - self.copy("*.pdb", dst=binDir, keep_path=False) + # Generate CMake toolchain file + tc = CMakeToolchain(self) + tc.cache_variables["LIBCOSIM_BUILD_APIDOC"] = False + tc.cache_variables["LIBCOSIM_BUILD_TESTS"] = self._is_tests_enabled() + tc.cache_variables["LIBCOSIM_NO_FMI_LOGGING"] = self.options.no_fmi_logging + tc.cache_variables["LIBCOSIM_WITH_PROXYFMU"] = self.options.proxyfmu + tc.generate() + CMakeDeps(self).generate() - def configure_cmake(self): + def build(self): cmake = CMake(self) - cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" - cmake.definitions["LIBCOSIM_BUILD_APIDOC"] = "OFF" - cmake.definitions["LIBCOSIM_BUILD_TESTS"] = self.is_tests_enabled() - cmake.definitions["BUILD_SHARED_LIBS"] = self.options.shared - cmake.definitions["LIBCOSIM_NO_FMI_LOGGING"] = self.options.no_fmi_logging - if self.options.proxyfmu: - cmake.definitions["LIBCOSIM_WITH_PROXYFMU"] = "ON" cmake.configure() - return cmake - - def build(self): - cmake = self.configure_cmake() cmake.build() - if self.is_tests_enabled(): - env_run = RunEnvironment(self) - with tools.environment_append(env_run.vars): - cmake.test(output_on_failure=True) - + if self._is_tests_enabled(): + env = VirtualRunEnv(self).environment() + env.define("CTEST_OUTPUT_ON_FAILURE", "ON") + with env.vars(self).apply(): + cmake.test() def package(self): - cmake = self.configure_cmake() + cmake = CMake(self) cmake.install() def package_info(self): self.cpp_info.libs = ["cosim"] + self.cpp_info.set_property("cmake_target_name", "libcosim::cosim") + # Tell consumers to use "our" CMake package config file. + self.cpp_info.builddirs.append(".") + self.cpp_info.set_property("cmake_find_mode", "none") + + def validate(self): + if self.options.shared and not self.dependencies["boost"].options.shared: + raise ConanInvalidConfiguration("Option libcosim:shared=True also requires option boost:shared=True") + + # Helper functions + + def _is_tests_enabled(self): + return os.getenv("LIBCOSIM_RUN_TESTS_ON_CONAN_BUILD", "False").lower() in ("true", "1") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 64bd88a97..da962f741 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -172,17 +172,19 @@ target_link_libraries(cosim Boost::boost Boost::date_time Boost::log - gsl - PRIVATE + Microsoft.GSL::GSL + # PRIVATE # Temporarily disabled due to https://github.com/conan-io/conan/issues/13302 ${FMILibrary_LIBRARIES} - libzip::libzip + libzip::zip XercesC::XercesC yaml-cpp ) if(LIBCOSIM_WITH_PROXYFMU) target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") - target_link_libraries(cosim PRIVATE proxyfmu::proxyfmu-client) + # The following dependency should be PRIVATE, but this has temporarily been + # disabled due to https://github.com/conan-io/conan/issues/13302 + target_link_libraries(cosim PUBLIC proxyfmu::proxyfmu-client) endif () if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") diff --git a/src/cosim/fmi/importer.cpp b/src/cosim/fmi/importer.cpp index f8ff6a184..9e4fa90a4 100644 --- a/src/cosim/fmi/importer.cpp +++ b/src/cosim/fmi/importer.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/cosim/fmi/v1/fmu.cpp b/src/cosim/fmi/v1/fmu.cpp index eb0cf62aa..f7fc72cc4 100644 --- a/src/cosim/fmi/v1/fmu.cpp +++ b/src/cosim/fmi/v1/fmu.cpp @@ -13,7 +13,7 @@ #include "cosim/fmi/windows.hpp" #include "cosim/log/logger.hpp" -#include +#include #include #include @@ -433,7 +433,7 @@ void slave_instance::get_boolean_variables( make_error_code(errc::model_error), last_log_record(instanceName_).message); } - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { values[i] = (fmiValues[i] != fmi1_false); } } @@ -453,7 +453,7 @@ void slave_instance::get_string_variables( make_error_code(errc::model_error), last_log_record(instanceName_).message); } - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { values[i] = (fmiValues[i] == nullptr) ? std::string() : std::string(fmiValues[i]); } @@ -507,7 +507,7 @@ void slave_instance::set_boolean_variables( COSIM_INPUT_CHECK(variables.size() == values.size()); if (variables.empty()) return; std::vector fmiValues(values.size()); - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { fmiValues[i] = static_cast(values[i] ? fmi1_true : fmi1_false); } @@ -532,7 +532,7 @@ void slave_instance::set_string_variables( COSIM_INPUT_CHECK(variables.size() == values.size()); if (variables.empty()) return; std::vector fmiValues(values.size()); - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { fmiValues[i] = values[i].c_str(); } const auto status = fmi1_import_set_string( diff --git a/src/cosim/fmi/v2/fmu.cpp b/src/cosim/fmi/v2/fmu.cpp index c15890389..7267c3804 100644 --- a/src/cosim/fmi/v2/fmu.cpp +++ b/src/cosim/fmi/v2/fmu.cpp @@ -13,7 +13,7 @@ #include "cosim/fmi/windows.hpp" #include "cosim/log/logger.hpp" -#include +#include #include #include @@ -453,7 +453,7 @@ void slave_instance::get_boolean_variables( make_error_code(errc::model_error), last_log_record(instanceName_).message); } - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { values[i] = (fmiValues[i] != fmi2_false); } } @@ -473,7 +473,7 @@ void slave_instance::get_string_variables( make_error_code(errc::model_error), last_log_record(instanceName_).message); } - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { values[i] = (fmiValues[i] == nullptr) ? std::string() : std::string(fmiValues[i]); } @@ -527,7 +527,7 @@ void slave_instance::set_boolean_variables( COSIM_INPUT_CHECK(variables.size() == values.size()); if (variables.empty()) return; std::vector fmiValues(values.size()); - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { fmiValues[i] = static_cast(values[i] ? fmi2_true : fmi2_false); } @@ -552,7 +552,7 @@ void slave_instance::set_string_variables( COSIM_INPUT_CHECK(variables.size() == values.size()); if (variables.empty()) return; std::vector fmiValues(values.size()); - for (int i = 0; i < values.size(); ++i) { + for (std::size_t i = 0; i < values.size(); ++i) { fmiValues[i] = values[i].c_str(); } const auto status = fmi2_import_set_string( diff --git a/src/cosim/observer/slave_value_provider.cpp b/src/cosim/observer/slave_value_provider.cpp index ec25eeea3..14e60d1ff 100644 --- a/src/cosim/observer/slave_value_provider.cpp +++ b/src/cosim/observer/slave_value_provider.cpp @@ -24,7 +24,7 @@ void get( if (samples.empty()) { throw std::out_of_range("no samples available"); } - for (int i = 0; i < values.size(); i++) { + for (std::size_t i = 0; i < values.size(); i++) { value_reference valueRef = variables[i]; values[i] = samples.at(valueRef); } diff --git a/src/cosim/observer/time_series_observer.cpp b/src/cosim/observer/time_series_observer.cpp index 9717d0a39..09d40b8b3 100644 --- a/src/cosim/observer/time_series_observer.cpp +++ b/src/cosim/observer/time_series_observer.cpp @@ -27,7 +27,7 @@ size_t get_samples( gsl::span steps, gsl::span times) { - size_t samplesRead = 0; + std::size_t samplesRead = 0; const auto& samplesIt = variables.find(valueReference); if (samplesIt != variables.end()) { const auto& samples = samplesIt->second; @@ -41,8 +41,8 @@ size_t get_samples( sampleIt = samples.upper_bound(fromStep); } } - for (samplesRead = 0; samplesRead < static_cast(values.size()); samplesRead++) { - if ((sampleIt != samples.end()) && (sampleIt->first < fromStep + values.size())) { + for (samplesRead = 0; samplesRead < values.size(); samplesRead++) { + if ((sampleIt != samples.end()) && (sampleIt->first < fromStep + static_cast(values.size()))) { steps[samplesRead] = sampleIt->first; values[samplesRead] = sampleIt->second; times[samplesRead] = timeSamples[sampleIt->first]; diff --git a/tests/mock_slave.hpp b/tests/mock_slave.hpp index 946db458c..eeb8f1a14 100644 --- a/tests/mock_slave.hpp +++ b/tests/mock_slave.hpp @@ -115,7 +115,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) const override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == real_out_reference) { values[i] = realOp_ ? realOp_(currentTime_, realIn_) : realIn_; } else if (variables[i] == real_in_reference) { @@ -130,7 +130,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) const override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == integer_out_reference) { values[i] = intOp_ ? intOp_(currentTime_, intIn_) : intIn_; } else if (variables[i] == integer_in_reference) { @@ -145,7 +145,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) const override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == boolean_out_reference) { values[i] = boolOp_ ? boolOp_(currentTime_, boolIn_) : boolIn_; } else if (variables[i] == boolean_in_reference) { @@ -160,7 +160,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) const override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == string_out_reference) { values[i] = stringOp_ ? stringOp_(currentTime_, stringIn_) : stringIn_; } else if (variables[i] == string_in_reference) { @@ -175,7 +175,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == real_in_reference) { realIn_ = values[i]; } else { @@ -188,7 +188,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == integer_in_reference) { intIn_ = values[i]; } else { @@ -201,7 +201,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == boolean_in_reference) { boolIn_ = values[i]; } else { @@ -214,7 +214,7 @@ class mock_slave : public cosim::slave gsl::span variables, gsl::span values) override { - for (int i = 0; i < variables.size(); ++i) { + for (std::size_t i = 0; i < variables.size(); ++i) { if (variables[i] == string_in_reference) { stringIn_ = values[i]; } else { diff --git a/version.txt b/version.txt index d9df1bbc0..a3f5a8ed4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.11.0 +0.10.3