using cross emulator with custom target and ctest

First some info dump in case it may matter:

  • cmake: 3.21.1
  • generator: Unix Makefiles
  • host: linux
  • toolchain: mingw-w64
  • toolchain file contains: set(CMAKE_CROSSCOMPILING_EMULATOR "WINEPATH=Z:\\usr\\x86_64-w64-mingw32\\usr\\bin\\" "/usr/bin/wine")
    Winepath is required as there are a few dlls in the cross-root needed for the targets to run.
  • CMAKE_CROSSCOMPILING gets properly set to true

There are 2 goals here, the first is to run one of the build targets to generate some data using add_custom_target

add_custom_target(data.zip ALL
  COMMAND $<TARGET_FILE:myexe> arg1 argN)
add_dependencies(data.zip myexe)

How do I get cmake to run the the above using the emulator/wine? Based on scattered snippets in the official docs and SO posts it might just work. Unfortunately it does not. It’s as if the setting is ignored. Tried all sort of stuff, to no avail. Surely missing something possibly obvious.

The second goal is to run unit tests using the emulator by running ctest. The setup works well for native builds. If I run ctest using the cross toolchain file it looks for the test executables in the right place but doesn’t add the required file extension .exe to the path, and again the emulator setting is ignored.

CMAKE_CROSSCOMPILING_EMULATOR is, AFAIK, only used in tests or when CMake does its own “this is a target name” replacement. You’ll probably need to do:

add_custom_target(data.zip ALL
  COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:myexe> arg1 argN)
add_dependencies(data.zip myexe)

Thanks for the your answer.

So about add_custom_target above you say it could reasonably work just that it’s not yet implemented to your knowledge or the $<TARGET_FILE:myexe> isn’t sufficient to trigger a “this is a target name” replacement.

Working around it can certainly be done one way or another, I used the inelegant COMMAND run-my-command.sh for no better idea.


So test registered with add_test(test test.cpp) should use the emulator when running ctest from console, unfortunately I didn’t get that to work either. Further such tests get called by their unix path, ie no .exe is appended to those targets which cmake generated “knowing” it’s cross compiling to Windows.

I can work around this as well (an other shell script), just think it should probably be handled cleanly by cmake and I can’t figure out where I’m off in my attempt or whether it isn’t expected to work in the first place.

Regards

That shouldn’t be necessary according to the docs for add_custom_target(), which state:

If COMMAND specifies an executable target name (created by the add_executable() command), it will automatically be replaced by the location of the executable created at build time if either of the following is true:

  • The target is not being cross-compiled (i.e. the CMAKE_CROSSCOMPILING variable is not set to true).
  • New in version 3.6: The target is being cross-compiled and an emulator is provided (i.e. its CROSSCOMPILING_EMULATOR target property is set). In this case, the contents of CROSSCOMPILING_EMULATOR will be prepended to the command before the location of the target executable.

In other words, I would expect the following to automatically prepend the emulator if one is set on the myexe target:

add_custom_target(data.zip ALL
  COMMAND myexe arg1 argN
)
1 Like

Thanks

add_custom_target(data.zip ALL
  COMMAND myexe arg1 argN
)

Triggers the “run with emulator”.

So explicit specification of target with $<TARGET_FILE:myexe> doesn’t work, only implicit specification. This is unexpected from a user point of view I’d argue and not easy to infer how to get it to work. Any chance this could be fixed reasonably in a future version?

For other readers my CROSSCOMPILING_EMULATOR setting above is treated as a list but doesn’t get expanded. So had to place it into an external wrapper script and use this as emulator which is at least easy to infer.

#!/usr/bin/env sh
WINEPATH=$(winepath -w /usr/x86_64-w64-mingw32/usr/bin/) /usr/bin/wine $1

This leaves the the tests which seems to be a different issue.

Regards

Ok, tracked it down to CXXTEST_ADD_TEST macro. As above only with magic substitution will the emulator be triggered.

Either FindCxxTest module is to be considered broken or cmake needs to become more clever about what is a previously built target.

Marking as solved.

Thanks to all participants. Regards