-
Notifications
You must be signed in to change notification settings - Fork 37
Description
Describe the bug
When cross-compiling FMIL for Windows on a Linux Host, an incorrect CMake configuration causes the library to search for FMU binaries in the linux64 directory instead of win64.
To Reproduce
Run the following Dockerfile on Windows, with an output directory at the same level. This checks out the latest FMIL, fetches reference FMUs, sets up the cross-compilation toolchain, and exports the build folder to output.
docker build --progress=plain -t fmil-test:latest --output output .
Then, run in the output folder: .\fmi_import_test.exe .\fmus\2.0\BouncingBall.fmu
# Troubleshoot cross-compiling fmi-library
FROM ubuntu:24.04 AS build
RUN apt update && export DEBIAN_FRONTEND=noninteractive \
&& apt -y install --no-install-recommends wget git ninja-build cmake g++-mingw-w64 zip unzip \
&& apt clean all \
&& rm -rf /var/lib/apt/lists
# Check out b711f5d
RUN git clone --depth 1 --branch master https://github.com/modelon-community/fmi-library.git \
&& cd fmi-library \
&& git reset --hard b711f5d
WORKDIR /fmi-library
RUN wget https://github.com/modelica/Reference-FMUs/releases/download/v0.0.39/Reference-FMUs-0.0.39.zip
RUN unzip Reference-FMUs-0.0.39.zip -d ./fmus
RUN <<HEREDOC cat > mingw-w64-x86_64.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
# cross compilers to use for C, C++
set(CMAKE_C_COMPILER \${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER \${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER \${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
set(CMAKE_FIND_ROOT_PATH /usr/\${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
# search for programs in the build host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# search for headers/libs in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
HEREDOC
RUN cat -e mingw-w64-x86_64.cmake
ENV CMAKE_TOOLCHAIN_FILE="/fmi-library/mingw-w64-x86_64.cmake"
RUN printenv
# Patch fmi_import_test.c to avoid non-portable temp dir
RUN cat -e Test/fmi_import_test.c
RUN <<"HEREDOC" cat > patch-tempdir.diff
diff --git a/Test/fmi_import_test.c b/Test/fmi_import_test.c
index c24190d..b8139d4 100644
--- a/Test/fmi_import_test.c
+++ b/Test/fmi_import_test.c
@@ -69 +69 @@ int main(int argc, char *argv[])
- tmpPath = fmi_import_mk_temp_dir(&callbacks, FMU_UNPACK_DIR, NULL);
+ tmpPath = fmi_import_mk_temp_dir(&callbacks, NULL, NULL);
HEREDOC
RUN cat -e patch-tempdir.diff
# This needed to avoid line-ending differences making a patch unapplicable
RUN apt update && apt install -y dos2unix patch
RUN unix2dos patch-tempdir.diff
# patch is more resilient w.r.t. line endings than git apply
RUN patch -p1 --binary < patch-tempdir.diff
RUN ls -la
# this produces a failing executable
RUN cmake -S . -B crossbuild -G Ninja
# this works around the problem, demonstrating that cross-compilation works
#RUN cmake -S . -B crossbuild -G Ninja -D FMILIB_FMI2_PLATFORM=win64
RUN cmake --build crossbuild --target fmi_import_test
# Export build artifacts with --output argument
FROM scratch
COPY --from=build /fmi-library/crossbuild /
COPY --from=build /fmi-library/fmus /fmusObserved behavior
The exe run fails because it's wrongly looking for the dll in the linux64 directory:
.\fmi_import_test.exe .\fmus\2.0\BouncingBall.fmu
module = FMILIB, log level = 5: Allocating FMIL context
module = FMILIB, log level = 5: Detecting FMI standard version
module = FMIZIP, log level = 5: Unpacking FMU into C:\Users\myuser\AppData\Local\Temp\fmila20492
module = FMIXML, log level = 5: Parsing XML to detect FMI standard version
module = FMIXML, log level = 5: XML specifies FMI 2.0
module = FMILIB, log level = 4: XML specifies FMI standard version 2.0
module = FMILIB, log level = 5: Detecting FMI standard version
module = FMIXML, log level = 5: Parsing XML to detect FMI standard version
module = FMIXML, log level = 5: XML specifies FMI 2.0
module = FMILIB, log level = 4: XML specifies FMI standard version 2.0
module = FMILIB, log level = 5: Parsing model description XML
module = FMI2XML, log level = 5: Parsing XML element fmiModelDescription
module = FMI2XML, log level = 5: Parsing XML element ModelExchange
module = FMI2XML, log level = 5: Parsing XML element CoSimulation
module = FMI2XML, log level = 5: Parsing XML element UnitDefinitions
module = FMI2XML, log level = 5: Parsing XML element TypeDefinitions
module = FMI2XML, log level = 5: Parsing XML element LogCategories
module = FMI2XML, log level = 5: Parsing XML element ModelVariables
module = FMI2XML, log level = 5: Building alias index
module = FMI2XML, log level = 5: Parsing XML element ModelStructure
module = FMI2XML, log level = 5: Parsing XML element Outputs
module = FMI2XML, log level = 5: Parsing XML element Derivatives
module = FMI2XML, log level = 5: Parsing XML element InitialUnknowns
module = FMI2XML, log level = 4: Found model identifiers for ModelExchange and CoSimulation
module = FMIXML, log level = 4: Could not find or open terminalsAndIcons.xml: 'C:\Users\myuser\AppData\Local\Temp\fmila20492/terminalsAndIcons\terminalsAndIcons.xml'. Continuing.
module = FMILIB, log level = 5: Parsing finished successfully
Model name: BouncingBall
Model identifier for ME: BouncingBall
Model GUID: {1AE5E10D-9521-4DE3-80B9-D0EAAA7D5AF1}
module = FMILIB, log level = 4: Loading 'linux64' binary with 'default' platform types
module = FMICAPI, log level = 1: Could not load the FMU binary: The specified module could not be found.
Could not create the DLL loading mechanism(C-API).
module = JMPRT, log level = 5: Removing C:\Users\myuser\AppData\Local\Temp\fmila20492
Press 'Enter' to exit
Expected behavior
This is expected to run correctly, and can be made so by manually overriding the platform variable as a workaround:
#RUN cmake -S . -B crossbuild -G Ninja -D FMILIB_FMI2_PLATFORM=win64
module = FMILIB, log level = 4: Loading 'win64' binary with 'default' platform types
module = FMICAPI, log level = 5: Loaded FMU binary from C:\Users\myuser\AppData\Local\Temp\fmila29512\binaries\win64\BouncingBall.dll
module = FMICAPI, log level = 5: Loading functions for the model exchange interface
module = FMILIB, log level = 5: Successfully loaded all the interface functions
Version returned from FMU: 2.0
module = FMILIB, log level = 5: Releasing FMU CAPI interface
module = FMICAPI, log level = 5: Successfully unloaded FMU binary
module = FMILIB, log level = 5: Releasing allocated library resources
module = JMPRT, log level = 5: Removing C:\Users\myuser\AppData\Local\Temp\fmila29512
Everything seems to be OK since you got this far=)!
Press 'Enter' to exit
The reason behind the error is that
- platform = FMI2_PLATFORM ends up being "linux64", not as expected "win64", because
fmilib_config.h:57has#define FMI2_PLATFORM "linux64"(FMI_FILE_SEP \\andFMI_DLL_EXT .dllare correct, though!), because- config_fmilib.h.cmake has
#define FMI2_PLATFORM "@FMI2_PLATFORM@", which is ultimately set by Config.cmake/fmiplatform.cmake, which usesCMAKE_HOST_WIN32instead ofWIN32andCMAKE_HOST_SYSTEM_NAMEinsteadCMAKE_SYSTEM_NAME(AFAICT both changes would be correct, as it's not the host system that is relevant)
Versions
- Version b711f5d
- Windows 11
Additional context/problems
- There is a non-fatal problem because of a mangled path, could probably be cleaned up at the same time:
Could not find or open terminalsAndIcons.xml: 'C:\Users\myuser\AppData\Local\Temp\fmila20492/terminalsAndIcons\terminalsAndIcons.xml'. Continuing.
- The proposed workaround is only for FMI2
- I don't know if
HOSTvariables should be adapted elsewhere in the CMake setup - Contrary to @jschueller's remark at Cross compilation compatible #96 (comment),
-DFMILIB_EXTERNAL_LIBS=ONis not necessary, and in fact needs to beOFF, because cross-compiled external libs are not available (at least not on Ubuntu). I think the root cause behind this recommendation was that no other way was visible to propagate the cross-compilation toolchain settings to the whole build. Exporting aCMAKE_TOOLCHAIN_FILEenv variable as in the repro above solves that problem. fmi_import_test.ccontains a temporary path (viaFMU_UNPACK_DIR) that is hardcoded to somewhere on the (Linux) host system, making it un-runnable on Windows. The rough patch avoid that issue.