2

My configuration has CMake 3.6, Visual Studio 2015 and latest Google test from GitHub. I add my unit tests through one of my cmake functions addGtest and do the build. After this I can run the test from my RUN_TESTS target or using ctrl + F5 in VS and works as expected.

The final goal is to run the unit tests at build time using the CMake dependency management. For now, as a first step, I have enhanced my function to create a custom_target (included the entire function, in case there are unforeseen issues in the working part), but not build it:

function (addGtest)
  # vvvv this part works as explained vvvv #
  set (optBOOLS)
  set (optSINGLES EXE)
  set (optLISTS DLL_LIST)
  cmake_parse_arguments (myARGS
    "${optBOOLS}" "${optSINGLES}" "${optLISTS}" ${ARGN})

  # addExecutable is a function that adds target executables
  set(myARGS_DLL_LIST gtest_main gtest "${myARGS_DLL_LIST}")
  addExecutable (EXE ${myARGS_EXE} DLL_LIST ${myARGS_DLL_LIST} ${myARGS_UNPARSED_ARGUMENTS})
  add_test (NAME ${myARGS_EXE} COMMAND ${myARGS_EXE} WORKING_DIRECTORY
    ${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
  ) # so it can be run using ctest
  # ^^^^ this part works as explained ^^^^ #

  add_custom_target (${myARGS_EXE}.tgt DEPENDS ${myARGS_EXE}
    COMMAND ${myARGS_EXE} --gtest_output="xml:${myARGS_EXE}.xml"
    WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
  )
endfunction (addGtest)

As expected when I perform the build, a new target, say, utMyTest.tgt is added to VS, but it is not built. Now when I build this new target by hand in VS, I expect that the test will be run. But it doesn't and gives the following error:

1>  The filename, directory name, or volume label syntax is incorrect.

I tried providing full path to the COMMAND option, removing double quotes around --gtest_output value, but to no avail. On the other hand when I cd to the working directory in a command line window and invoke the exe, it works fine!!

The first question is how do I fix it to run the test by building this new target? After that, I plan to add_custom_target (${myARGS_EXE}.run) and add_dependencies (${myARGS_EXE}.run ${myARGS_EXE}.tgt). Would this then run the test whenever the exe changes? Or should I do something else? Thank you for your help.

Andrew
  • 101
  • 1
  • 10
NameRakes
  • 463
  • 6
  • 12
  • 1
    Have you tried to remove all variable's dereferences and generator expressions from your `add_custom_target` call, and **hardcode all arguments** for this call? Such way is common when *debug* problems, probably related with variable's dereference. – Tsyvarev Oct 17 '16 at 07:39
  • 1
    The CMake documentation of the `COMMAND` option of the `add_custom_target` command says it can use generator expressions, but that is *not mentioned* in the `WORKING DIRECTORY` option. If I hardcode the working directory path, then building the target executes the gtest. Will do some more research / debugging and post any useful info. Thank you. – NameRakes Oct 17 '16 at 13:47
  • Good cacth. Actually, CMake documentation **explicitely** says, which option may use generator expression. As there is no such notion about `WORKING_DIRECTORY` option for command `add_custom_target`, generator expressions cannot be used for it. Interestingly same option for `add_test` may use generator expression (and it is explicitely described in docs). – Tsyvarev Oct 17 '16 at 14:07
  • `@Tsyvarev`, I figured out that `CMAKE_CFG_INTDIR` could be used in lieu of generator expressions. But more details are in the answer. Thanks for the idea of hardcoding the variables. Please feel free to improve my answer below. – NameRakes Oct 17 '16 at 17:14

1 Answers1

0

Could not add so much details in the comment, hence this answer.

1. Answer to the original problem

Since I needed the configuration dependent path in the WORKING_DIRECTORY option of the add_custom_target command, but cannot pass generator expressions to it, the idea is to use the CMAKE_CFG_INTDIR variable so:

add_custom_target (${myARGS_EXE}.tgt
  DEPENDS ${myARGS_EXE}
  COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
  WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin
)

Now, when you build the above target, the unit test is run in the WORKING_DIRECTORY which is not entirely desirable, since that is the install directory for libs and exes. It would be really nice to ...

2. Run the unit test from its build directory

While, at the same time, picking up the DLL paths from within Visual Studio, and storing the Gtest generated .xml file in the build directory. This is the solution:

In CMake version 3.10 CMAKE_MSVCIDE_RUN_PATH property was added. In the project wide CMakeLists.txt, set(CMAKE_MSVCIDE_RUN_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin) - thanks to this solution #3, we can appendPATH to point to our install directory. And then replace the above add_custom_target command with this:

add_custom_command (
  TARGET ${myARGS_EXE} POST_BUILD
  COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
)

This solution avoids the mess of creating additional targets. Clearly only when myARGS_EXE is built, the unit test is run. Obviously myARGS_EXE's transitive dependency on other DLLs is covered also.

If you have other elegant solutions, please post.

Community
  • 1
  • 1
NameRakes
  • 463
  • 6
  • 12