cmake_minimum_required(VERSION 3.5)

set(FMU_NAME FmuExportCrossCompile)

set(FMU_NAME_HASH 164)

# build the project with fmu hash string to make shorter paths (e.g) ToroidalCoreQuadraticCrossSection.dir => 759.dir
project(${FMU_NAME_HASH} C)

set(CMAKE_BUILD_TYPE Release)

# FMU compilation options
set(COMPILE_MODELICA_EXTERNAL_C
    OFF
    CACHE BOOL
    "Add Modelica External C sources to build target if 'ON'.")
set(BUILD_SHARED_LIBS
    ON
    CACHE BOOL
    "Compile DLL/Shared Object binary object if 'ON', compile static binary object if 'OFF'.")
set(FMI_INTERFACE_HEADER_FILES_DIRECTORY
    "${CMAKE_CURRENT_SOURCE_DIR}/fmi"
    CACHE STRING
    "Path to FMI header files containing fmi2Functions.h, fmi2FunctionTypes.h, fmi2TypesPlatforms.h")
set(RUNTIME_DEPENDENCIES_LEVEL
    "modelica"
    CACHE STRING
    "Add modelica runtime dependencies to FMU if set to 'modelica'. Add system runtime dependencies as well if set to 'all'.")
set(NEED_CVODE
    OFF
    CACHE BOOL
    "FMU needs to link to SUNDIALS CVODE if 'ON'. Used for CoSimulation FMUs that want to use CVODE as integrator. Use 'OFF' otherwise.")
set(CVODE_DIRECTORY
    ""
    CACHE STRING
    "IF CVODE is needed provide a directory where to find it.")

if(NOT ${CMAKE_VERSION} VERSION_LESS "4.3")
  cmake_policy(SET CMP0207 NEW)
endif()

# CMake cannot resolve runtime dependencies of a foreign platform, it rejects
# install(TARGETS ... RUNTIME_DEPENDENCIES) with "not supported when cross-compiling".
# Install the external libraries we linked against directly instead, so a cross
# compiled FMU still ships them.
set(OM_INSTALL_LINKED_DEPENDENCIES OFF)
if(CMAKE_CROSSCOMPILING AND NOT RUNTIME_DEPENDENCIES_LEVEL STREQUAL "none")
  message(STATUS "Cross compiling: installing the linked external libraries instead of "
                 "resolving runtime dependencies.")
  set(OM_INSTALL_LINKED_DEPENDENCIES ON)
  set(RUNTIME_DEPENDENCIES_LEVEL "none")
endif()

# Test if RUNTIME_DEPENDENCIES is needed and available
if(${CMAKE_VERSION} VERSION_LESS "3.21" AND NOT ${RUNTIME_DEPENDENCIES_LEVEL} STREQUAL "none")
  message(FATAL_ERROR
          "--fmuRuntimeDepends=${RUNTIME_DEPENDENCIES_LEVEL} requires CMake version 3.21 or higher.\n"
          "You are running version ${CMAKE_VERSION}.\n"
          "Use OpenModelica compiler flag '--fmuRuntimeDepends=none' to disable including runtime dependencies into FMU.")
endif()

# On musl libc (e.g. Alpine), ldconfig is a BusyBox applet that doesn't support
# "-p" (needed by install(... RUNTIME_DEPENDENCIES ...) below). It silently
# ignores the flag and exits 0 with empty stdout, so check for empty output
# too and fall back to not bundling runtime dependencies instead of failing.
if(UNIX AND NOT APPLE AND NOT RUNTIME_DEPENDENCIES_LEVEL STREQUAL "none")
  find_program(OMC_LDCONFIG_EXECUTABLE ldconfig PATHS /sbin /usr/sbin)
  if(OMC_LDCONFIG_EXECUTABLE)
    execute_process(
      COMMAND ${OMC_LDCONFIG_EXECUTABLE} -p
      RESULT_VARIABLE OMC_LDCONFIG_P_RESULT
      OUTPUT_VARIABLE OMC_LDCONFIG_P_OUTPUT
      ERROR_QUIET)
    string(STRIP "${OMC_LDCONFIG_P_OUTPUT}" OMC_LDCONFIG_P_OUTPUT)
    if(NOT OMC_LDCONFIG_P_RESULT EQUAL 0 OR OMC_LDCONFIG_P_OUTPUT STREQUAL "")
      message(WARNING
              "ldconfig does not support '-p' (likely musl libc, e.g. Alpine). "
              "CMake's runtime dependency resolution needs this, so falling back "
              "to RUNTIME_DEPENDENCIES_LEVEL=none for this FMU. Use "
              "--fmuRuntimeDepends=none to silence this warning.")
      set(RUNTIME_DEPENDENCIES_LEVEL "none")
    endif()
  endif()
endif()

# Create position independent code for static libraries
if(NOT BUILD_SHARED_LIBS)
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

# Export all symbols on Windows
if(MSVC)
  set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

# FMI header files
if(NOT FMI_INTERFACE_HEADER_FILES_DIRECTORY)
  message(FATAL_ERROR "No FMI export headers provided. Set -DFMI_INTERFACE_HEADER_FILES_DIRECTORY=/path/to/fmi/headers")
endif()
find_file(FMI2_FUNCTIONS_H "fmi2Functions.h"
          PATHS ${FMI_INTERFACE_HEADER_FILES_DIRECTORY}
          NO_DEFAULT_PATH,
          NO_CMAKE_FIND_ROOT_PATH)
if(NOT FMI2_FUNCTIONS_H)
  message(FATAL_ERROR "Could not find fmi2Functions.h in FMI_INTERFACE_HEADER_FILES_DIRECTORY=${FMI_INTERFACE_HEADER_FILES_DIRECTORY}")
endif()
message(STATUS "FMI2 include directory: ${FMI_INTERFACE_HEADER_FILES_DIRECTORY}")


# Look for a threading library and see if it is PThreads.
find_package(Threads)
# If we find a threading library and it is PThreads then we enable its usage.
if(Threads_FOUND AND CMAKE_USE_PTHREADS_INIT)
  set(OM_HAVE_PTHREADS ON)
# Otherwise threading will be disabled.
else()
  set(OM_HAVE_PTHREADS OFF)
endif()

# Source files
file(GLOB_RECURSE FMU_RUNTIME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/external_solvers/*.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/fmi-export/*.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/gc/*.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/math-support/pivot.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/meta/*.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/simulation/*.c
                                      ${CMAKE_CURRENT_SOURCE_DIR}/util/*.c)
if(${COMPILE_MODELICA_EXTERNAL_C})
  list(APPEND FMU_RUNTIME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ModelicaExternalC/ModelicaStandardTables.c
                                  ${CMAKE_CURRENT_SOURCE_DIR}/ModelicaExternalC/ModelicaStandardTablesDummyUsertab.c
                                  ${CMAKE_CURRENT_SOURCE_DIR}/ModelicaExternalC/snprintf.c
                                  ${CMAKE_CURRENT_SOURCE_DIR}/ModelicaExternalC/ModelicaIO.c
                                  ${CMAKE_CURRENT_SOURCE_DIR}/ModelicaExternalC/ModelicaMatIO.c)
endif()
if(NOT ${NEED_CVODE})
  list(REMOVE_ITEM FMU_RUNTIME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/simulation/solver/sundials_error.c
                                       ${CMAKE_CURRENT_SOURCE_DIR}/simulation/solver/cvode_solver.c)
endif()
file(GLOB FMU_GENERATED_MODEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
# <Model>_info.c is not a standalone translation unit; it is a bare string literal that gets
# #included into <Model>_init_fmu.c (used by FMI 1.0). Remove it from the compiled sources so
# it is not built on its own. See https://github.com/OpenModelica/OpenModelica/issues/15838
file(GLOB FMU_GENERATED_INCLUDE_ONLY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*_info.c)
if(FMU_GENERATED_INCLUDE_ONLY_SOURCES)
  list(REMOVE_ITEM FMU_GENERATED_MODEL_SOURCES ${FMU_GENERATED_INCLUDE_ONLY_SOURCES})
endif()

# Set install prefix to FMU target system short and architecture
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
  set(FMU_TARGET_SYSTEM_NAME "win")
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
  set(FMU_TARGET_SYSTEM_NAME "linux")
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
  set(FMU_TARGET_SYSTEM_NAME "darwin")
else()
  message(FATAL_ERROR "Unknown target system: ${CMAKE_SYSTEM_NAME}")
endif()

# Normalized target architecture, e.g. x86_64 or i686.
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" FMU_TARGET_ARCH)
if(FMU_TARGET_ARCH STREQUAL "amd64")
  set(FMU_TARGET_ARCH "x86_64")
elseif(FMU_TARGET_ARCH STREQUAL "arm64")
  set(FMU_TARGET_ARCH "aarch64")
elseif(FMU_TARGET_ARCH STREQUAL "")
  if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
    set(FMU_TARGET_ARCH "x86_64")
  else()
    set(FMU_TARGET_ARCH "i686")
  endif()
endif()

if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/isfmi3")
  # FMI 3.0 uses the platform tuple "{architecture}-{os}" for the binaries folder
  # (e.g. x86_64-linux), unlike FMI 1.0/2.0 which use "{os}{bitness}" (e.g. linux64).
  # The two schemes do not spell Windows the same way: FMI 1.0/2.0 want "win"
  # (win64), FMI 3.0 wants it in full (x86_64-windows). Linux and darwin are the
  # same word in both, so only this one has to be translated.
  set(FMU_TARGET_SYSTEM_TUPLE "${FMU_TARGET_SYSTEM_NAME}")
  if(FMU_TARGET_SYSTEM_NAME STREQUAL "win")
    set(FMU_TARGET_SYSTEM_TUPLE "windows")
  endif()
  set(FMU_TARGET_PLATFORM "${FMU_TARGET_ARCH}-${FMU_TARGET_SYSTEM_TUPLE}")
elseif(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
  set(FMU_TARGET_PLATFORM "${FMU_TARGET_SYSTEM_NAME}64")
else()
  set(FMU_TARGET_PLATFORM "${FMU_TARGET_SYSTEM_NAME}32")
endif()

message(STATUS "Building for FMI platform ${FMU_TARGET_PLATFORM}")

set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/../binaries/${FMU_TARGET_PLATFORM})
set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX})
set(CMAKE_INSTALL_BINDIR ${CMAKE_INSTALL_PREFIX})
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(CMAKE_STATIC_LIBRARY_PREFIX "")
message(STATUS "Install directory: ${CMAKE_INSTALL_PREFIX}")

# Set RPATH
if(APPLE)
  set(CMAKE_INSTALL_RPATH "@loader_path")
else()
  if(${NEED_CVODE} AND RUNTIME_DEPENDENCIES_LEVEL STREQUAL "none")
    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH True)
  endif()
  set(CMAKE_INSTALL_RPATH "$ORIGIN")
endif()

# Target library
add_library(${FMU_NAME_HASH}
            ${FMU_RUNTIME_SOURCES}
            ${FMU_GENERATED_MODEL_SOURCES})

# Set output name for the .dll's and .so files to use the full FMU name instead of fmu hash string
set_target_properties(${FMU_NAME_HASH} PROPERTIES OUTPUT_NAME ${FMU_NAME})

# Linker options
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.13")
  if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
    target_link_options(${FMU_NAME_HASH} PRIVATE "LINKER:SHELL:--no-undefined")
  endif()
  # A cross compiled Windows FMU cannot collect the MinGW runtime DLLs (libgcc,
  # libwinpthread) the way install(TARGETS ... RUNTIME_DEPENDENCIES) would, so link
  # them statically. Otherwise the FMU only loads on machines that have MinGW installed.
  if(MINGW AND CMAKE_CROSSCOMPILING)
    target_link_options(${FMU_NAME_HASH} PRIVATE "-static-libgcc" "-static")
  endif()
endif()

# If we have PThreads support, define OM_HAVE_PTHREADS and link to the imported threading library.
if(OM_HAVE_PTHREADS)
  target_compile_definitions(${FMU_NAME_HASH} PRIVATE OM_HAVE_PTHREADS)
  target_link_libraries(${FMU_NAME_HASH} PRIVATE Threads::Threads)
endif()

# If not using MSVC, link to the math library libm.
if(NOT MSVC)
  target_link_libraries(${FMU_NAME_HASH} PRIVATE m)
endif()

# Directory names Modelica libraries use for platform specific binaries, both the
# "{os}{bitness}" (win64) and the "{architecture}-{os}" (x86_64-windows) flavour.
set(OM_LIBRARY_PLATFORM_DIR_REGEX
    "^((win|linux|darwin)(32|64)|(x86_64|amd64|i386|i686|aarch64|arm)-(windows|linux|darwin))$")

# The external library directories below were resolved for the platform the FMU
# sources were generated on. When cross compiling we have to look into the
# Resources/Library sub directory of the *target* platform instead, e.g.
# Resources/Library/win64 instead of Resources/Library/linux64.
# See https://github.com/OpenModelica/OpenModelica/issues/9509
macro(om_add_target_library_directories _om_var)
  set(_om_target_subdirs "${FMU_TARGET_PLATFORM}"
                         "${FMU_TARGET_ARCH}-${FMU_TARGET_SYSTEM_NAME}")
  if(WIN32)
    list(APPEND _om_target_subdirs "${FMU_TARGET_ARCH}-windows")
  endif()

  # Library root directories to look into: every listed directory that is not
  # platform specific, plus the parent of every platform specific one.
  set(_om_roots "")
  set(_om_keep "")
  foreach(_om_dir IN LISTS ${_om_var})
    string(REGEX REPLACE "/+$" "" _om_dir "${_om_dir}")
    if(_om_dir STREQUAL "")
      continue()
    endif()
    get_filename_component(_om_base "${_om_dir}" NAME)
    if(_om_base MATCHES "${OM_LIBRARY_PLATFORM_DIR_REGEX}")
      get_filename_component(_om_parent "${_om_dir}" DIRECTORY)
      list(APPEND _om_roots "${_om_parent}")
      if(CMAKE_CROSSCOMPILING AND NOT "${_om_base}" IN_LIST _om_target_subdirs)
        # Binaries of a different platform, searching them would find the wrong library.
        continue()
      endif()
    else()
      list(APPEND _om_roots "${_om_dir}")
    endif()
    list(APPEND _om_keep "${_om_dir}")
  endforeach()
  list(REMOVE_DUPLICATES _om_roots)

  set(_om_target_dirs "")
  foreach(_om_root IN LISTS _om_roots)
    foreach(_om_sub IN LISTS _om_target_subdirs)
      if(IS_DIRECTORY "${_om_root}/${_om_sub}")
        list(APPEND _om_target_dirs "${_om_root}/${_om_sub}")
      endif()
    endforeach()
  endforeach()
  if(_om_target_dirs)
    list(REMOVE_DUPLICATES _om_target_dirs)
    message(STATUS "Target platform library directories: ${_om_target_dirs}")
  endif()

  # Target specific directories take precedence over the generic ones.
  set(${_om_var} ${_om_target_dirs} ${_om_keep})
  list(REMOVE_DUPLICATES ${_om_var})
endmacro()

set(EXTERNAL_LIBDIRECTORIES "${DOCKER_VOL_DIR}/var/lib/jenkins/ws/OpenModelica_PR-16453/build/bin/../bin"
                            "${DOCKER_VOL_DIR}/var/lib/jenkins/ws/OpenModelica_PR-16453/build/bin/../lib/${CMAKE_LIBRARY_ARCHITECTURE}/omc")
om_add_target_library_directories(EXTERNAL_LIBDIRECTORIES)

# Cross-Platform CMAKE_FIND_LIBRARY_SUFFIXES
if(WIN32)
  set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll" ".a")
elseif(APPLE)
  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".a")
else()
  set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
endif()



if(${NEED_CVODE})
  # Force static compilation on Windows or if CMake is too old
  if(WIN32 OR (${CMAKE_VERSION} VERSION_LESS "3.21" AND NOT ${RUNTIME_DEPENDENCIES_LEVEL} STREQUAL "none"))
    set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib)
    target_compile_definitions(${FMU_NAME_HASH} PRIVATE SUNDIALS_STATIC_DEFINE)
  endif()

  message(STATUS "CVODE_DIRECTORY: ${CVODE_DIRECTORY}")
  find_library(SUNDIALS_CVODE_LIBRARY sundials_cvode
               PATHS ${CVODE_DIRECTORY}
               NO_DEFAULT_PATH
               NO_SYSTEM_ENVIRONMENT_PATH
               NO_CMAKE_FIND_ROOT_PATH
               REQUIRED)
  if(NOT SUNDIALS_CVODE_LIBRARY)
    message(FATAL_ERROR "Couldn't find library sundials_cvode in ${CVODE_DIRECTORY}")
  endif()
  message(STATUS "SUNDIALS_CVODE_LIBRARY: ${SUNDIALS_CVODE_LIBRARY}")
  list(APPEND RUNTIME_DEPENDS ${SUNDIALS_CVODE_LIBRARY})

  find_library(SUNDIALS_NVECSERIAL_LIBRARY sundials_nvecserial
               PATHS ${CVODE_DIRECTORY}
               NO_DEFAULT_PATH
               NO_SYSTEM_ENVIRONMENT_PATH
               NO_CMAKE_FIND_ROOT_PATH
               REQUIRED)
  if(NOT SUNDIALS_NVECSERIAL_LIBRARY)
    message(FATAL_ERROR "Couldn't find library sundials_nvecserial in ${CVODE_DIRECTORY}")
  endif()
  message(STATUS "SUNDIALS_NVECSERIAL_LIBRARY: ${SUNDIALS_NVECSERIAL_LIBRARY}")
  list(APPEND RUNTIME_DEPENDS ${SUNDIALS_NVECSERIAL_LIBRARY})

  find_library(SUNDIALS_CORE_LIBRARY sundials_core
               PATHS ${CVODE_DIRECTORY}
               NO_DEFAULT_PATH
               NO_SYSTEM_ENVIRONMENT_PATH
               NO_CMAKE_FIND_ROOT_PATH
               REQUIRED)
  if(NOT SUNDIALS_CORE_LIBRARY)
    message(FATAL_ERROR "Couldn't find library sundials_core in ${CVODE_DIRECTORY}")
  endif()
  message(STATUS "SUNDIALS_CORE_LIBRARY: ${SUNDIALS_CORE_LIBRARY}")
  list(APPEND RUNTIME_DEPENDS ${SUNDIALS_CORE_LIBRARY})

  # Order matters for static libraries: cvode and nvecserial both pull symbols out
  # of sundials_core, so core has to come last.
  target_link_libraries(${FMU_NAME_HASH} PRIVATE ${SUNDIALS_NVECSERIAL_LIBRARY})
  target_link_libraries(${FMU_NAME_HASH} PRIVATE ${SUNDIALS_CVODE_LIBRARY})
  target_link_libraries(${FMU_NAME_HASH} PRIVATE ${SUNDIALS_CORE_LIBRARY})
  target_include_directories(${FMU_NAME_HASH} PRIVATE sundials)
  set(WITH_SUNDIALS ";WITH_SUNDIALS")
  message(STATUS "CVODE: ${SUNDIALS_NVECSERIAL_LIBRARY} ${SUNDIALS_CVODE_LIBRARY} ${SUNDIALS_CORE_LIBRARY}")
else()
  message(STATUS "CVODE: Not linked")
endif()

# Add include directories
target_include_directories(${FMU_NAME_HASH} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${FMU_NAME_HASH} PRIVATE ${FMI_INTERFACE_HEADER_FILES_DIRECTORY}
                                               sundials)

# Set compiler definitions
target_compile_definitions(${FMU_NAME_HASH} PRIVATE OMC_MINIMAL_RUNTIME=1;OMC_FMI_RUNTIME=1;CMINPACK_NO_DLL${WITH_SUNDIALS})

if(BUILD_SHARED_LIBS)
  # Override FMI2_FUNCTION_PREFIX if FMU compiled dynamically (shared-library FMUs
  # must export the plain, unprefixed fmiX function names).
  target_compile_definitions(${FMU_NAME_HASH} PRIVATE FMI2_OVERRIDE_FUNCTION_PREFIX)
  if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/isfmi3")
    target_compile_definitions(${FMU_NAME_HASH} PRIVATE FMI3_OVERRIDE_FUNCTION_PREFIX)
  endif()
  message(STATUS "Not using FMI2_FUNCTION_PREFIX / FMI3_FUNCTION_PREFIX")
else()
  message(STATUS "Using FMI2_FUNCTION_PREFIX / FMI3_FUNCTION_PREFIX")
endif()

# Install target
if(RUNTIME_DEPENDENCIES_LEVEL STREQUAL "all")
  install(TARGETS ${FMU_NAME_HASH}
    RUNTIME_DEPENDENCIES
      DIRECTORIES ${EXTERNAL_LIBDIRECTORIES} ${CVODE_DIRECTORY}
    PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
    FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR})
elseif(RUNTIME_DEPENDENCIES_LEVEL STREQUAL "modelica")
  message(STATUS "Installing dynamic dependencies from list: ${RUNTIME_DEPENDS}")
  install(TARGETS ${FMU_NAME_HASH}
    RUNTIME_DEPENDENCIES
      DIRECTORIES ${EXTERNAL_LIBDIRECTORIES} ${CVODE_DIRECTORY}
      PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
      POST_EXCLUDE_REGEXES "^\\/lib.*" "^\\/usr\\/lib.*" "^\\/usr\\/local\\/lib.*" ".*system32/.*\\.dll"
      POST_INCLUDE_FILES ${RUNTIME_DEPENDS}
    PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
    FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR})
else()
  install(TARGETS ${FMU_NAME_HASH}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

if(OM_INSTALL_LINKED_DEPENDENCIES)
  # Only shared libraries, static ones are already part of the FMU binary.
  set(OM_LINKED_SHARED_DEPENDENCIES "")
  foreach(_om_dep IN LISTS RUNTIME_DEPENDS)
    get_filename_component(_om_dep_name "${_om_dep}" NAME)
    if(_om_dep_name MATCHES "\\.(dll|dylib|so)$" OR _om_dep_name MATCHES "\\.so\\.")
      # The FMU binary references the library by its SONAME (libFoo.so.1.2.3), not by
      # the link name (libFoo.so) find_library returned, so take the versioned
      # siblings along as well.
      get_filename_component(_om_dep_dir "${_om_dep}" DIRECTORY)
      file(GLOB _om_dep_files "${_om_dep_dir}/${_om_dep_name}" "${_om_dep_dir}/${_om_dep_name}.*")
      list(APPEND OM_LINKED_SHARED_DEPENDENCIES ${_om_dep_files})
    endif()
  endforeach()
  if(OM_LINKED_SHARED_DEPENDENCIES)
    list(REMOVE_DUPLICATES OM_LINKED_SHARED_DEPENDENCIES)
    message(STATUS "Installing external libraries: ${OM_LINKED_SHARED_DEPENDENCIES}")
    install(FILES ${OM_LINKED_SHARED_DEPENDENCIES}
      PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
      DESTINATION ${CMAKE_INSTALL_LIBDIR})
  endif()
endif()

# Zip target creating modelname.fmu
add_custom_target(create_fmu
    COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target install
    COMMAND "${CMAKE_COMMAND}" -E tar "cfv" "../FmuExportCrossCompile.fmu" --format=zip
      "binaries/"
      "resources/"
      "sources/"
      "modelDescription.xml"
    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../")
