-2

I am writing software for a platform that has both 64-bit and 32-bit cores and I want to write unit tests for both sets of software using googletest. I want to build the tests so that the tests for the 64-bit software are also built 64-bit and similarly 32-bit tests should be built 32-bit. This means that googletest has to be built separately 64 & 32-bit for both targets. I have been able to write CMakeLists that accomplish this when built separately, but when I create a main CMakeLists.txt file in the parent directory that includes all subdirectories the build fails because googletest is only built once and linking fails when because of architecture incompatibilities.

I am using vscode and I would like to be able to compile all tests for both architectures at once without having to manually change the cmake.sourceDirectory in vscode cmake extension and compile each target separately. I know I could just manually compile separate 32 & 64 bit libraries, add them to my project structure and configure CMake to link to those but I wouldn't want to add those libraries (and gtest headers) to my git-repository. I prefer using the CMake FetchContent feature to get and compile them on demand. Basically I would like two compile and build each target separately instead of first compiling all targets and then linking them which it seems to do now. Is this possible?

I am pretty much a noob with CMake so I feel like I'm just missing something obvious and there's some easy way of doing what I want.

Here's a simple example project that I've been playing around with trying to get this to work. My actual project has similar structure but has multiple 64-bit targets and one 32-bit target:

├─ CMakeLists.txt
├─ test32/
   ├─ CMakeLists.txt
   ├─ src/
      ├─ calc32.c
      ├─ calc32.h
   ├─ tests/
      ├─ tests32.cpp
      ├─ unit_tests_main.cpp
└─ test64/
   ├─ CMakeLists.txt
   ├─ src/
      ├─ calc64.c
      ├─ calc64.h
   ├─ tests/
      ├─ tests64.cpp
      ├─ unit_tests_main.cpp

The src-folders contain the application software that I'm trying to write tests for and the tests-folders contain the tests. The calc32 & 64 files just contain a single function that adds two integer parameters together and returns the result and the tests32 & 64 files each have a simple test that tests that the functions indeed return the result of the addition. Unit_tests_main.cpp-files have the gtest main function.

The root CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)

project(tests)

add_subdirectory("test32")
add_subdirectory("test64")

The test32 CMakeLists.txt:

project(test32)

cmake_minimum_required(VERSION 3.14)

set(EXEC_NAME "calc32")
set(TEST_EXEC_NAME "calc32_tests")
set(TEST_DIR "./tests")
set(SRC_DIR "./src")

include(GoogleTest)
include(FetchContent)

enable_testing()

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git 
    GIT_TAG v1.13.0
)

FetchContent_MakeAvailable(googletest)

add_executable(${TEST_EXEC_NAME}
    ${TEST_DIR}/unit_tests_main.cpp
)

# Trigger 32 bit build for both gtest & application
set_target_properties(gtest PROPERTIES COMPILE_OPTIONS "-m32" LINK_FLAGS "-m32")
set_target_properties(${TEST_EXEC_NAME} PROPERTIES COMPILE_OPTIONS "-m32" LINK_FLAGS     "-m32")

# Add the files that contain your tests here
target_sources(${TEST_EXEC_NAME} PUBLIC
    ${TEST_DIR}/tests32.cpp
)

# Add the source files under test and their dependencies here
target_sources(${TEST_EXEC_NAME} PUBLIC
    ${SRC_DIR}/calc32.c
)

target_include_directories(${TEST_EXEC_NAME} PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR};
    ${SRC_DIR};
)

target_link_libraries(
    ${TEST_EXEC_NAME}
    gtest
)

gtest_discover_tests(${TEST_EXEC_NAME})

and finally the test64 CMakeLists.txt

project(test64)

cmake_minimum_required(VERSION 3.14)

set(EXEC_NAME "calc64")
set(TEST_EXEC_NAME "calc64_tests")
set(TEST_DIR "./tests")
set(SRC_DIR "./src")

include(GoogleTest)
include(FetchContent)

enable_testing()

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git 
    GIT_TAG v1.13.0
)

FetchContent_MakeAvailable(googletest)

add_executable(${TEST_EXEC_NAME}
    ${TEST_DIR}/unit_tests_main.cpp
)

# Add the files that contain your tests here
target_sources(${TEST_EXEC_NAME} PUBLIC
    ${TEST_DIR}/tests64.cpp
)

# Add the source files under test and their dependencies here
target_sources(${TEST_EXEC_NAME} PUBLIC
    ${SRC_DIR}/calc64.c
)

target_include_directories(${TEST_EXEC_NAME} PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR};
    ${SRC_DIR};
)

target_link_libraries(
    ${TEST_EXEC_NAME}
    gtest
)

gtest_discover_tests(${TEST_EXEC_NAME})

As you can see they are pretty much identical except for the two extra set_target_properties-lines in the 32-bit CMakeLists.txt

273K
  • 29,503
  • 10
  • 41
  • 64
Nr7
  • 29
  • 1
  • 6
  • 4
    You cannot compile the same target (e.g. `gtest`) in two different configurations at once. I know none CMake project which creates different target names for different bitness. You are better to create a toolchain file for 32-bit target (like [that one](https://stackoverflow.com/a/28047073/3440745)) and build your project **twice**: once without toolchain for native 64bit, and once with the toolchain for 32bit. If some your code is applicable only for 32bit or only for 64bit, then you could use corresponding conditionals. – Tsyvarev Mar 02 '23 at 14:12
  • If you're using Visual Studio to compile, I believe you can just use the architecture argument of the configure command ([`-A`](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-A)) – starball Mar 02 '23 at 22:47
  • @Tsyvarev Thanks, I'll check out the toolchain approach. I'll might still go and compile manually two separate gtest libs and add those to the project like I mentioned in my initial post. It's a bit hacky but at least I can compile everything at once. – Nr7 Mar 03 '23 at 16:18
  • @user I'm using Visual Studio Code, not Visual Studio. And yeah, I know you can do this with VS. I've actually done that before in an earlier project but we're developing on Linux in this project so that's not really a feasible now. – Nr7 Mar 03 '23 at 16:21

1 Answers1

1

If resource and memory are not a major concern for testing purposes, the suggested solution of having separate googletest32 and googletest64 subdirectories and builds would actually be preferable, especially in terms of avoiding unnecessary interdependencies between different testing environments.

For each environment, an option() can be defined in the CMake file that allows enabling and disabling the respective tests through the if() and endif() conditionals.

Should the need arise to consider other environments, then this decoupling allows you to independently add other tests.