diff --git a/OMCompiler/Compiler/Script/CevalScriptBackend.mo b/OMCompiler/Compiler/Script/CevalScriptBackend.mo index 54f3820746c..5fc798879b0 100644 --- a/OMCompiler/Compiler/Script/CevalScriptBackend.mo +++ b/OMCompiler/Compiler/Script/CevalScriptBackend.mo @@ -3543,6 +3543,182 @@ algorithm end if; end callTranslateModel; +protected function configureFMU_cmake +"Configure and build binaries with CMake for target platform" + input String platform; + input String fmutmp; + input String fmuTargetName; + input String logfile; + input Boolean isWindows; +protected + String fmuSourceDir; + String CMAKE_GENERATOR = "", CMAKE_BUILD_TYPE; + String quote, dquote, defaultFmiIncludeDirectoy; +algorithm + fmuSourceDir := fmutmp+"/sources/"; + quote := "'"; + dquote := if isWindows then "\"" else "'"; + defaultFmiIncludeDirectoy := dquote + Settings.getInstallationDirectoryPath() + "/include/omc/c/fmi" + dquote; + + // Set build type + if Flags.getConfigEnum(Flags.FMI_FILTER) == Flags.FMI_BLACKBOX or Flags.getConfigEnum(Flags.FMI_FILTER) == Flags.FMI_PROTECTED then + CMAKE_BUILD_TYPE := "-DCMAKE_BUILD_TYPE=Release"; + elseif Flags.isSet(Flags.GEN_DEBUG_SYMBOLS) then + CMAKE_BUILD_TYPE := "-DCMAKE_BUILD_TYPE=Debug"; + else + CMAKE_BUILD_TYPE := "-DCMAKE_BUILD_TYPE=RelWithDebInfo"; + end if; + + // Remove old log file + if System.regularFileExists(logfile) then + System.removeFile(logfile); + end if; + + _ := match Util.stringSplitAtChar(platform, " ") + local + String cmd; + String cmakeCall; + String crossTriple, buildDir, fmiTarget; + list dockerImgArgs; + Integer uid; + String cidFile, volumeID, containerID, userID; + String dockerLogFile; + case {"dynamic"} + algorithm + if isWindows then + CMAKE_GENERATOR := "-G MSYS Makefiles "; + end if; + buildDir := "build_cmake_dynamic"; + cmakeCall := "cmake " + CMAKE_GENERATOR + + "-DFMI_INTERFACE_HEADER_FILES_DIRECTORY=" + defaultFmiIncludeDirectoy + " " + + CMAKE_BUILD_TYPE + + " .."; + cmd := "cd \"" + fmuSourceDir + "\" && " + + "mkdir " + buildDir + " && cd " + buildDir + " && " + + cmakeCall + " && " + + "cmake --build . --target install && " + + "cd .. && rm -rf " + buildDir; + if 0 <> System.systemCall(cmd, outFile=logfile) then + Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)}); + System.removeFile(logfile); + fail(); + end if; + then(); + case crossTriple::"docker"::"run"::dockerImgArgs + algorithm + uid := System.getuid(); + cidFile := fmutmp+".cidfile"; + + // Temp log file outside of Docker volume + dockerLogFile := crossTriple + ".tmp.log"; + + // Create a docker volume for the FMU since we can't forward volumes + // to the docker run command depending on where the FMU was generated (inside another volume) + cmd := "docker volume create"; + runDockerCmd(cmd, dockerLogFile); + volumeID := List.last(System.strtok(System.readFile(dockerLogFile), "\n")); + + if System.regularFileExists(cidFile) then + System.removeFile(cidFile); + end if; + cmd := "docker run --cidfile " + cidFile + " -v " + volumeID + ":/data busybox true"; + runDockerCmd(cmd, dockerLogFile, true, volumeID, ""); + + containerID := System.trim(System.readFile(cidFile)); + System.removeFile(cidFile); + + // Copy the FMU contents to the container + cmd := "docker cp " + fmutmp + " " + containerID + ":/data"; + runDockerCmd(cmd, dockerLogFile, cleanup=true, volumeID=volumeID, containerID=containerID); + + // Copy the FMI headers to the container + cmd := "docker cp " + defaultFmiIncludeDirectoy + " " + containerID + ":/data/fmiInclude"; + runDockerCmd(cmd, dockerLogFile, cleanup=true, volumeID=volumeID, containerID=containerID); + + // Build for target host + userID := (if uid<>0 then "--user " + String(uid) else ""); + buildDir := "build_cmake_" + crossTriple; + if 0 <> System.regex(crossTriple, "mingw", 1) then + fmiTarget := " -DCMAKE_SYSTEM_NAME=Windows "; + elseif 0 <> System.regex(crossTriple, "apple", 1) then + fmiTarget := " -DCMAKE_SYSTEM_NAME=Darwin "; + else + fmiTarget := ""; + end if; + cmakeCall := "cmake -DFMI_INTERFACE_HEADER_FILES_DIRECTORY=/fmu/fmiInclude " + + fmiTarget + + CMAKE_BUILD_TYPE + + " .."; + cmd := "docker run " + userID + " --rm -w /fmu -v " + volumeID + ":/fmu -e CROSS_TRIPLE=" + crossTriple + " " + stringDelimitList(dockerImgArgs," ") + + " sh -c " + dquote + + "cd " + dquote + "/fmu/" + fmuSourceDir + dquote + " && " + + "mkdir " + buildDir + " && cd " + buildDir + " && " + + cmakeCall + " && " + + "cmake --build . && make install && " + + "cd .. && rm -rf " + buildDir + + dquote; + runDockerCmd(cmd, dockerLogFile, cleanup=true, volumeID=volumeID, containerID=containerID); + + // Copy the files back from the volume (via the container) to the filesystem. + // Docker cp can't handle too long names on Windows. + // Workaround: Zip it in the container, copy it to host, unzip it + if isWindows then + cmd := "docker run " + userID + " --rm -w /fmu -v " + volumeID + ":/fmu " + stringDelimitList(dockerImgArgs," ") + + " tar -zcf comp-fmutmp.tar.gz " + fmutmp; + runDockerCmd(cmd, dockerLogFile, cleanup=true, volumeID=volumeID, containerID=containerID); + + cmd := "docker cp " + containerID + ":/data/comp-fmutmp.tar.gz ."; + runDockerCmd(cmd, dockerLogFile, cleanup=true, volumeID=volumeID, containerID=containerID); + System.systemCall("tar zxf comp-fmutmp.tar.gz && rm comp-fmutmp.tar.gz"); + else + cmd := "docker cp " + containerID + ":/data/" + fmutmp + "/ ."; + runDockerCmd(cmd, dockerLogFile, cleanup=false, volumeID=volumeID, containerID=containerID); + end if; + + // Cleanup + System.systemCall("docker rm " + containerID); + System.systemCall("docker volume rm " + volumeID); + + // Copy log file into resources directory + System.copyFile(dockerLogFile, logfile); + System.removeFile(dockerLogFile); + then(); + else + algorithm + Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {"Unknown/unsupported platform \"" + platform + " \" for CMake FMU build"}); + then fail(); + end match; +end configureFMU_cmake; + +protected function runDockerCmd + "Run a docker command. Can clean up volumen and container on failure." + input String cmd; + input String logfile; + input Boolean cleanup = false; + input String volumeID = ""; + input String containerID = ""; +protected + Boolean verbose = false; +algorithm + System.appendFile(logfile, cmd + "\n"); + if 0 <> System.systemCall(cmd, outFile=logfile) then + Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {cmd + " failed:\n" + System.readFile(logfile)}); + + if cleanup then + if not stringEqual(containerID, "") then + System.systemCall("docker rm " + containerID); + end if; + if not stringEqual(volumeID, "") then + System.systemCall("docker volume rm " + volumeID); + end if; + end if; + + fail(); + elseif verbose then + print(System.readFile(logfile) +"\n"); + end if; +end runDockerCmd; + protected function configureFMU "Configures Makefile.in of FMU for traget configuration." input String platform; @@ -3808,10 +3984,10 @@ protected SimCode.SimulationSettings simSettings; list libs; Boolean isWindows; + Boolean useCrossCompileCmake = false; list fmiFlagsList; Boolean needs3rdPartyLibs; String FMUType = inFMUType; - algorithm cache := inCache; if not FMI.checkFMIVersion(FMUVersion) then @@ -3900,10 +4076,42 @@ algorithm needs3rdPartyLibs := false; end if; + // Use CMake on Windows when cross-compiling with docker + _ := match (Flags.getConfigString(Flags.FMU_CMAKE_BUILD), needs3rdPartyLibs) + case ("true", _) algorithm + useCrossCompileCmake := true; + then(); + case ("false", _) algorithm + useCrossCompileCmake := false; + then(); + case ("default", false) algorithm + if (listLength(platforms) > 1 and isWindows) then + Error.addCompilerNotification("OS is Windows and multiple platform detected. Using CMake to build FMU."); + useCrossCompileCmake := true; + else + for platform in platforms loop + if isWindows and 1 == System.regex(platform, " docker run ", 0, true, false) then + Error.addCompilerNotification("OS is Windows and docker platform detected. Using CMake to build FMU."); + useCrossCompileCmake := true; + end if; + end for; + end if; + then(); + else + algorithm + useCrossCompileCmake := false; + then(); + end match; + + // Configure the FMU Makefile for platform in platforms loop configureLogFile := System.realpath(fmutmp)+"/resources/"+System.stringReplace(listGet(Util.stringSplitAtChar(platform," "),1),"/","-")+".log"; - configureFMU(platform, fmutmp, configureLogFile, isWindows, needs3rdPartyLibs); + if useCrossCompileCmake then + configureFMU_cmake(platform, fmutmp, filenameprefix, configureLogFile, isWindows); + else + configureFMU(platform, fmutmp, configureLogFile, isWindows, needs3rdPartyLibs); + end if; if Flags.getConfigEnum(Flags.FMI_FILTER) == Flags.FMI_BLACKBOX or Flags.getConfigEnum(Flags.FMI_FILTER) == Flags.FMI_PROTECTED then System.removeFile(configureLogFile); end if; diff --git a/OMCompiler/Compiler/SimCode/SimCodeMain.mo b/OMCompiler/Compiler/SimCode/SimCodeMain.mo index ffc08a90738..13ce5e5fe79 100644 --- a/OMCompiler/Compiler/SimCode/SimCodeMain.mo +++ b/OMCompiler/Compiler/SimCode/SimCodeMain.mo @@ -742,7 +742,8 @@ algorithm Boolean b; Boolean needSundials = false; String fileprefix; - String install_include_omc_dir, install_include_omc_c_dir, install_fmu_sources_dir, fmu_tmp_sources_dir; + String install_include_omc_dir, install_include_omc_c_dir, install_share_buildproject_dir, install_fmu_sources_dir, fmu_tmp_sources_dir; + String cmakelistsStr; list sourceFiles, model_desc_src_files; list dgesv_sources, cminpack_sources, simrt_c_sundials_sources, simrt_linear_solver_sources, simrt_non_linear_solver_sources; list simrt_mixed_solver_sources, fmi_export_files, model_gen_files, model_all_gen_files, shared_source_files; @@ -816,6 +817,7 @@ algorithm install_include_omc_dir := Settings.getInstallationDirectoryPath() + "/include/omc/"; install_include_omc_c_dir := install_include_omc_dir + "c/"; + install_share_buildproject_dir := Settings.getInstallationDirectoryPath() + "/share/omc/runtime/c/fmi/buildproject/"; install_fmu_sources_dir := Settings.getInstallationDirectoryPath() + RuntimeSources.fmu_sources_dir; fmu_tmp_sources_dir := fmutmp + "/sources/"; @@ -892,6 +894,13 @@ algorithm Tpl.tplNoret(function CodegenFMU.translateModel(in_a_FMUVersion=FMUVersion, in_a_FMUType=FMUType, in_a_sourceFiles=model_desc_src_files), simCode); + // Copy CMakeLists.txt.in and replace @FMU_NAME_IN@ with fmu name + System.copyFile(source = install_share_buildproject_dir + "CMakeLists.txt.in", + destination = fmu_tmp_sources_dir + "CMakeLists.txt"); + cmakelistsStr := System.readFile(fmu_tmp_sources_dir + "CMakeLists.txt"); + cmakelistsStr := System.stringReplace(cmakelistsStr, "@FMU_NAME_IN@", simCode.fileNamePrefix); + System.writeFile(fmu_tmp_sources_dir + "CMakeLists.txt", cmakelistsStr); + Tpl.closeFile(Tpl.tplCallWithFailErrorNoArg(function CodegenFMU.fmuMakefile(a_target=Config.simulationCodeTarget(), a_simCode=simCode, a_FMUVersion=FMUVersion, a_sourceFiles=model_all_gen_files, a_runtimeObjectFiles=list(System.stringReplace(f,".c",".o") for f in shared_source_files), a_dgesvObjectFiles=list(System.stringReplace(f,".c",".o") for f in dgesv_sources), a_cminpackObjectFiles=list(System.stringReplace(f,".c",".o") for f in cminpack_sources), a_sundialsObjectFiles=list(System.stringReplace(f,".c",".o") for f in simrt_c_sundials_sources)), txt=Tpl.redirectToFile(Tpl.emptyTxt, simCode.fileNamePrefix+".fmutmp/sources/Makefile.in"))); Tpl.closeFile(Tpl.tplCallWithFailError(CodegenFMU.settingsfile, simCode, diff --git a/OMCompiler/Compiler/Util/Flags.mo b/OMCompiler/Compiler/Util/Flags.mo index 979adfc6cdc..2f6fb8f2732 100644 --- a/OMCompiler/Compiler/Util/Flags.mo +++ b/OMCompiler/Compiler/Util/Flags.mo @@ -51,7 +51,7 @@ encapsulated package Flags To add a new flag, simply add a new constant of either DebugFlag or ConfigFlag type below, and then add it to either the allDebugFlags or allConfigFlags list - depending on which type it is. + (in FlagsUtil.mo), depending on which type it is. " public @@ -1360,19 +1360,28 @@ constant ConfigFlag FMI_FLAGS = CONFIG_FLAG(141, "fmiFlags", NONE(), EXTERNAL(), STRING_LIST_FLAG({}), NONE(), Gettext.gettext("Add simulation flags to FMU. Will create _flags.json in resources folder with given flags. Use --fmiFlags or --fmiFlags=none to disable [default]. Use --fmiFlags=default for the default simulation flags. To pass flags use e.g. --fmiFlags=s:cvode,nls:homotopy or --fmiFlags=path/to/yourFlags.json.")); -constant ConfigFlag NEW_BACKEND = CONFIG_FLAG(142, "newBackend", +constant ConfigFlag FMU_CMAKE_BUILD = CONFIG_FLAG(142, "fmuCMakeBuild", + NONE(), EXTERNAL(), STRING_FLAG("default"), + SOME(STRING_DESC_OPTION({ + ("default", Gettext.notrans("Let omc decide if CMake should be used.")), + ("true", Gettext.notrans("Use CMake to compile FMU binaries.")), + ("false", Gettext.notrans("Use default GNU Autoconf toolchain to compile FMU binaries.")) + })), + Gettext.gettext("Defines if FMUs will be configured and build with CMake.")); + +constant ConfigFlag NEW_BACKEND = CONFIG_FLAG(143, "newBackend", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Activates experimental new backend for better array handling. This also activates the new frontend. [WIP]")); -constant ConfigFlag PARMODAUTO = CONFIG_FLAG(143, "parmodauto", +constant ConfigFlag PARMODAUTO = CONFIG_FLAG(144, "parmodauto", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Experimental: Enable parallelization of independent systems of equations in the translated model.")); -constant ConfigFlag INTERACTIVE_PORT = CONFIG_FLAG(144, "interactivePort", +constant ConfigFlag INTERACTIVE_PORT = CONFIG_FLAG(145, "interactivePort", NONE(), EXTERNAL(), INT_FLAG(0), NONE(), Gettext.gettext("Sets the port used by the interactive server.")); -constant ConfigFlag ALLOW_NON_STANDARD_MODELICA = CONFIG_FLAG(145, "allowNonStandardModelica", +constant ConfigFlag ALLOW_NON_STANDARD_MODELICA = CONFIG_FLAG(146, "allowNonStandardModelica", NONE(), EXTERNAL(), STRING_LIST_FLAG({ }), SOME(STRING_DESC_OPTION({ @@ -1383,22 +1392,22 @@ constant ConfigFlag ALLOW_NON_STANDARD_MODELICA = CONFIG_FLAG(145, "allowNonStan })), Gettext.gettext("Flags to allow non-standard Modelica.")); -constant ConfigFlag EXPORT_CLOCKS_IN_MODELDESCRIPTION = CONFIG_FLAG(146, "exportClocksInModelDescription", +constant ConfigFlag EXPORT_CLOCKS_IN_MODELDESCRIPTION = CONFIG_FLAG(147, "exportClocksInModelDescription", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("exports clocks in modeldescription.xml for fmus, The default is false.")); -constant ConfigFlag LINK_TYPE = CONFIG_FLAG(147, "linkType", +constant ConfigFlag LINK_TYPE = CONFIG_FLAG(148, "linkType", NONE(), EXTERNAL(), ENUM_FLAG(1, {("dynamic",1), ("static",2)}), SOME(STRING_OPTION({"dynamic", "static"})), Gettext.gettext("Sets the link type for the simulation executable.\n"+ "dynamic: libraries are dynamically linked; the executable is built very fast but is not portable because of DLL dependencies.\n"+ "static: libraries are statically linked; the executable is built more slowly but it is portable and dependency-free.\n")); -constant ConfigFlag TEARING_ALWAYS_DERIVATIVES = CONFIG_FLAG(148, "tearingAlwaysDer", +constant ConfigFlag TEARING_ALWAYS_DERIVATIVES = CONFIG_FLAG(149, "tearingAlwaysDer", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Always choose state derivatives as iteration variables in strong components.")); -constant ConfigFlag DUMP_FLAT_MODEL = CONFIG_FLAG(149, "dumpFlatModel", +constant ConfigFlag DUMP_FLAT_MODEL = CONFIG_FLAG(150, "dumpFlatModel", NONE(), EXTERNAL(), STRING_LIST_FLAG({"all"}), SOME(STRING_DESC_OPTION({ ("flatten", Gettext.gettext("After flattening but before connection handling.")), @@ -1409,7 +1418,7 @@ constant ConfigFlag DUMP_FLAT_MODEL = CONFIG_FLAG(149, "dumpFlatModel", })), Gettext.gettext("Dumps the flat model at the given stages of the frontend.")); -constant ConfigFlag SIMULATION = CONFIG_FLAG(150, "simulation", +constant ConfigFlag SIMULATION = CONFIG_FLAG(151, "simulation", SOME("u"), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Simulates the last model in the given Modelica file.")); diff --git a/OMCompiler/Compiler/Util/FlagsUtil.mo b/OMCompiler/Compiler/Util/FlagsUtil.mo index d8a0d7be382..2944ed6f2bd 100644 --- a/OMCompiler/Compiler/Util/FlagsUtil.mo +++ b/OMCompiler/Compiler/Util/FlagsUtil.mo @@ -397,6 +397,7 @@ constant list allConfigFlags = { Flags.FMI_FILTER, Flags.FMI_SOURCES, Flags.FMI_FLAGS, + Flags.FMU_CMAKE_BUILD, Flags.NEW_BACKEND, Flags.PARMODAUTO, Flags.INTERACTIVE_PORT, diff --git a/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt b/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt index 510729b4474..fe806e1aa85 100644 --- a/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt +++ b/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt @@ -4,6 +4,7 @@ if(WIN32) install(FILES configure.ac + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in ## This should not be omc/runtime/c/fmi but rather omc/fmi. It is inconsistent DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/omc/runtime/c/fmi/buildproject ) @@ -32,6 +33,7 @@ else() ${OpenModelica_SOURCE_DIR}/common/config.sub ${OpenModelica_SOURCE_DIR}/common/config.guess ${OpenModelica_SOURCE_DIR}/common/install-sh + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in ## This should not be omc/runtime/c/fmi but rather omc/fmi. It is inconsistent DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/omc/runtime/c/fmi/buildproject ) diff --git a/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt.in b/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt.in new file mode 100644 index 00000000000..0d47c073ae8 --- /dev/null +++ b/OMCompiler/SimulationRuntime/fmi/export/buildproject/CMakeLists.txt.in @@ -0,0 +1,70 @@ + +cmake_minimum_required(VERSION 3.7) + +set(FMU_NAME @FMU_NAME_IN@) + +project(${FMU_NAME}) + +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() + +set(THREADS_PTHREAD_ARG "2" CACHE STRING "Forcibly set by CMakeLists.txt." FORCE) +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +file(GLOB_RECURSE FMU_RUNTIME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/external_solvers/*.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) + +file(GLOB FMU_GENERATED_MODEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c) + +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() + +if(${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 "") +add_library(${FMU_NAME} SHARED + ${FMU_RUNTIME_SOURCES} + ${FMU_GENERATED_MODEL_SOURCES}) + + +target_link_libraries(${FMU_NAME} PRIVATE Threads::Threads) + +target_include_directories(${FMU_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(${FMU_NAME} PRIVATE ${FMI_INTERFACE_HEADER_FILES_DIRECTORY}) + +target_compile_definitions(${FMU_NAME} PRIVATE -DOMC_MINIMAL_RUNTIME=1 -DOMC_FMI_RUNTIME=1 -DCMINPACK_NO_DLL) + +install(TARGETS ${FMU_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +add_custom_target(create_zip COMMAND + ${CMAKE_COMMAND} -E tar "cfv" "../${CMAKE_PROJECT_NAME}.fmu" --format=zip + "binaries/" + "resources/" + "sources/" + "modelDescription.xml" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../") diff --git a/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.in b/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.in index cf06c960dd4..c7573014c50 100644 --- a/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.in +++ b/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.in @@ -12,7 +12,7 @@ configure: configure.ac $(top_builddir)/m4/lapack.m4 install: all mkdir -p $(PROJECTDIR) - cp -a configure "$(top_builddir)/config.guess" "$(top_builddir)/config.sub" "$(top_builddir)/install-sh" $(PROJECTDIR)/ + cp -a configure "$(top_builddir)/config.guess" "$(top_builddir)/config.sub" "$(top_builddir)/install-sh" CMakeLists.txt.in $(PROJECTDIR)/ Makefile: Makefile.in cd "$(top_builddir)" && ./config.status diff --git a/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.omdev.mingw b/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.omdev.mingw index fc24384dea4..2fd25531486 100644 --- a/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.omdev.mingw +++ b/OMCompiler/SimulationRuntime/fmi/export/buildproject/Makefile.omdev.mingw @@ -7,4 +7,4 @@ default: install install: mkdir -p $(PROJECTDIR) - cp -a configure.ac $(PROJECTDIR)/ + cp -a configure.ac CMakeLists.txt.in $(PROJECTDIR)/ diff --git a/testsuite/special/FmuExportCrossCompile/CMakeCrossCompile.mos b/testsuite/special/FmuExportCrossCompile/CMakeCrossCompile.mos new file mode 100644 index 00000000000..dc4f2536fdc --- /dev/null +++ b/testsuite/special/FmuExportCrossCompile/CMakeCrossCompile.mos @@ -0,0 +1,28 @@ +// status: correct +// Note: Requires docker in PATH +// +// Test cross compilation with CMake FMU build using multiarch/crossbuild image. + +if not loadModel(Modelica, {"4.0.0"}) then + print(getErrorString()); + exit(1); +end if; + +system("rm -rf CMakeCrossCompile && mkdir CMakeCrossCompile", "CMakeCrossCompile.log"); +cd("CMakeCrossCompile"); + +// Set CMake FMU without any filters +if not setCommandLineOptions("--fmuCMakeBuild=true --fmiFilter=none") then + print(getErrorString()); + exit(1); +end if; + +// Build FMU +platforms := { + "x86_64-apple-darwin docker run multiarch/crossbuild", + "x86_64-linux-gnu docker run multiarch/crossbuild", + "i686-linux-gnu docker run docker.openmodelica.org/build-deps:v1.13-i386", + "x86_64-w64-mingw32 docker run multiarch/crossbuild", + "i686-w64-mingw32 docker run multiarch/crossbuild"}; +buildModelFMU(Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum, version="2.0", fmuType="me_cs", platforms=platforms); getErrorString(); + diff --git a/testsuite/special/FmuExportCrossCompile/Makefile b/testsuite/special/FmuExportCrossCompile/Makefile index 7ea0c88f2be..58093142005 100644 --- a/testsuite/special/FmuExportCrossCompile/Makefile +++ b/testsuite/special/FmuExportCrossCompile/Makefile @@ -1,4 +1,4 @@ -.PHONE: clean test +.PHONE: clean test fmuExportCrossCompile CMakeCrossCompile # Note: Requires PATH to include: # all cross-compilation targets (including OSX) @@ -7,20 +7,41 @@ OMC=../../../build/bin/omc test: clean - HOME=$(CURDIR)/../../libraries-for-testing/ $(OMC) fmuExportCrossCompile.mos - unzip -q FmuExportCrossCompile.fmu -d FmuExportCrossCompile.fmutmp - $(MAKE) check-files + $(MAKE) fmuExportCrossCompile + $(MAKE) CMakeCrossCompile + dockerpull: docker pull docker.openmodelica.org/osxcross-omsimulator:v2.0 docker pull docker.openmodelica.org/armcross-omsimulator:v2.0 docker pull docker.openmodelica.org/msyscross-omsimulator:v2.0 -check-files: + docker pull multiarch/crossbuild:latest + +fmuExportCrossCompile: + HOME=$(CURDIR)/../../libraries-for-testing/ $(OMC) fmuExportCrossCompile.mos + unzip -q FmuExportCrossCompile.fmu -d FmuExportCrossCompile.fmutmp + $(MAKE) check-FmuExportCrossCompile-files + +CMakeCrossCompile: + HOME=$(CURDIR)/../../libraries-for-testing/ $(OMC) CMakeCrossCompile.mos + unzip -qq CMakeCrossCompile/Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.fmu -d CMakeCrossCompile/Pendulum_FMU/ + $(MAKE) check-CMakeCrossCompile-files + +check-FmuExportCrossCompile-files: @file FmuExportCrossCompile.fmutmp/binaries/win32/FmuExportCrossCompile.dll | grep "PE32 executable (DLL) (console) Intel 80386, for MS Windows" || (file FmuExportCrossCompile.fmutmp/binaries/win32/FmuExportCrossCompile.dll ; false) @file FmuExportCrossCompile.fmutmp/binaries/win64/FmuExportCrossCompile.dll | grep "PE32+ executable (DLL) (console) x86-64, for MS Windows" || (file FmuExportCrossCompile.fmutmp/binaries/win64/FmuExportCrossCompile.dll ; false) @file FmuExportCrossCompile.fmutmp/binaries/darwin64/FmuExportCrossCompile.dylib | grep "Mach-O 64-bit x86_64 dynamically linked shared library" || (file FmuExportCrossCompile.fmutmp/binaries/darwin64/FmuExportCrossCompile.dylib ; false) @file FmuExportCrossCompile.fmutmp/binaries/linux32/FmuExportCrossCompile.so | grep "ELF *32-bit *LSB *shared *object, Intel 80386, version 1 (SYSV), dynamically linked" || (file FmuExportCrossCompile.fmutmp/binaries/linux32/FmuExportCrossCompile.so ; false) @file FmuExportCrossCompile.fmutmp/binaries/linux64/FmuExportCrossCompile.so | grep "ELF *64-bit *LSB *shared *object, x86-64, version 1 (SYSV), dynamically linked" || (file FmuExportCrossCompile.fmutmp/binaries/linux64/FmuExportCrossCompile.so ; false) @file FmuExportCrossCompile.fmutmp/binaries/arm-linux-gnueabihf/FmuExportCrossCompile.so | grep "ELF *32-bit *LSB *shared *object, ARM, EABI5 version 1 (SYSV), dynamically linked" || (file FmuExportCrossCompile.fmutmp/binaries/arm-linux-gnueabihf/FmuExportCrossCompile.so ; false) + +check-CMakeCrossCompile-files: + @file CMakeCrossCompile/Pendulum_FMU/binaries/win32/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dll | grep "PE32 executable (DLL) (console) Intel 80386, for MS Windows" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/win32/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dll ; false) + @file CMakeCrossCompile/Pendulum_FMU/binaries/win64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dll | grep "PE32+ executable (DLL) (console) x86-64, for MS Windows" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/win64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dll ; false) + @file CMakeCrossCompile/Pendulum_FMU/binaries/darwin64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dylib | grep "Mach-O 64-bit x86_64 dynamically linked shared library" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/darwin64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.dylib ; false) + @file CMakeCrossCompile/Pendulum_FMU/binaries/linux32/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so | grep "ELF *32-bit *LSB *shared *object, Intel 80386, version 1 (SYSV), dynamically linked" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/linux32/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so ; false) + @file CMakeCrossCompile/Pendulum_FMU/binaries/linux64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so | grep "ELF *64-bit *LSB *shared *object, x86-64, version 1 (SYSV), dynamically linked" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/linux64/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so ; false) +# @file CMakeCrossCompile/Pendulum_FMU/binaries/arm-linux-gnueabihf/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so | grep "ELF *32-bit *LSB *shared *object, ARM, EABI5 version 1 (SYSV), dynamically linked" || (file Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.fmutmp/binaries/arm-linux-gnueabihf/Modelica_Mechanics_MultiBody_Examples_Elementary_Pendulum.so ; false) + fmu-check: rm -rf ./Test_FMUs ./fmu-run.sh FmuExportCrossCompile @@ -30,3 +51,4 @@ fmu-check: $(OMC) check-files.mos clean: rm -rf *.json *.xml *.html *.fmu* *.c *.makefile *.log *.o *.libs *.h *.mat *.csv Test_FMUs + rm -rf CMakeCrossCompile/