Some times we might be working in a team, and that team has members who prefer
to use different IDEs or who develop on different platforms. In these cases we
can leverage CMake’s generators.
This is a short guide on using a generator for Xcode and adding a second
test file to break up testing.
Directory Structure
This is the structure that we start with.
❯ tree
├── CMakeLists.txt
├── README.md
├── src
│ ├── CMakeLists.txt
│ ├── Example.cpp
│ └── Example.hpp
└── tests
├── CMakeLists.txt
└── lib-tester.cpp
Using the Generator
There are a number of generators that can be used. They are documented here
There are a couple of ways to create the build directory. I am naming mine build-xcode here because by default, vscode creates a directory named build. Xcode and vscode can not use the same build directory.
It is generally recommended that the build directory not exist within the project directory when using CMake.
I am not following that advice here for simplicity.
- Using the B flag
❯ cmake -Bbuild-xcode -GXcode
-- The CXX compiler identification is AppleClang 13.0.0.13000029
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found GTest: /usr/local/lib/cmake/GTest/GTestConfig.cmake (found version "1.11.0")
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/aspann/Documents/Development/cpp/cmake-c++-template/build-xcode
- Create the build directory by hand.
❯ mkdir build-xcode && cd $_ && cmake .. -GXcode
-- The CXX compiler identification is AppleClang 13.0.0.13000029
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found GTest: /usr/local/lib/cmake/GTest/GTestConfig.cmake (found version "1.11.0")
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/aspann/Documents/Development/cpp/cmake-c++-template/build-xcode
This gives us the following.
❯ tree
├── C++-CMake-Library-Development.png
├── CMakeLists.txt
├── README.md
├── build-xcode
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.22.1
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ └── CompilerIdCXX
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ ├── CompilerIdCXX
│ │ │ ├── CompilerIdCXX.build
│ │ │ │ └── Debug
│ │ │ │ └── CompilerIdCXX.build
│ │ │ │ ├── CompilerIdCXX-all-non-framework-target-headers.hmap
│ │ │ │ ├── CompilerIdCXX-all-target-headers.hmap
│ │ │ │ ├── CompilerIdCXX-generated-files.hmap
│ │ │ │ ├── CompilerIdCXX-own-target-headers.hmap
│ │ │ │ ├── CompilerIdCXX-project-headers.hmap
│ │ │ │ ├── CompilerIdCXX.hmap
│ │ │ │ ├── Objects-normal
│ │ │ │ │ └── x86_64
│ │ │ │ │ ├── CMakeCXXCompilerId.d
│ │ │ │ │ ├── CMakeCXXCompilerId.dia
│ │ │ │ │ ├── CMakeCXXCompilerId.o
│ │ │ │ │ ├── CompilerIdCXX.LinkFileList
│ │ │ │ │ └── CompilerIdCXX_dependency_info.dat
│ │ │ │ ├── Script-2C8FEB8E15DC1A1A00E56A5D.sh
│ │ │ │ └── all-product-headers.yaml
│ │ │ ├── CompilerIdCXX.xcodeproj
│ │ │ │ └── project.pbxproj
│ │ │ ├── XCBuildData
│ │ │ │ ├── 3482802cdf712446fc88789941bc3089-buildRequest.json
│ │ │ │ ├── 3482802cdf712446fc88789941bc3089-desc.xcbuild
│ │ │ │ ├── 3482802cdf712446fc88789941bc3089-manifest.xcbuild
│ │ │ │ ├── 3482802cdf712446fc88789941bc3089-targetGraph.txt
│ │ │ │ ├── BuildDescriptionCacheIndex-b1f97e8c6205ba582a37b4bbb8d2d944
│ │ │ │ └── build.db
│ │ │ └── tmp
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── TargetDirectories.txt
│ │ └── cmake.check_cache
│ ├── CMakeScripts
│ │ └── ReRunCMake.make
│ ├── CTestTestfile.cmake
│ ├── cmake_install.cmake
│ ├── mylib.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ └── xcshareddata
│ │ └── WorkspaceSettings.xcsettings
│ ├── src
│ │ ├── CMakeFiles
│ │ ├── CTestTestfile.cmake
│ │ └── cmake_install.cmake
│ └── tests
│ ├── CMakeFiles
│ ├── CTestTestfile.cmake
│ └── cmake_install.cmake
├── src
│ ├── CMakeLists.txt
│ ├── Example.cpp
│ └── Example.hpp
└── tests
├── CMakeLists.txt
└── lib-tester.cpp
23 directories, 46 files
Opening the project in Xcode
The fastest way to do this is from in the build directory.
❯ open mylib.xcodeproj
This should give you something like this.
- Open the bottom panel and make sure that
All Output
is selected. - Make sure you have selected
Test1Tester
program as your target at the top centre of the editor and run the program to generate the output. You may need to run the program twice. Some oddity with Xcode.
This should give the following result.
Adding a New Test Program to our project.
It is often best to break your tests down into more manageable files. So I will make a new file for testing. This will done outside Xcode.
Update the CMakeLists.txt under tests
To keep things simple I am just adding a single program file lib-tester2.cpp
to the tests
directory and then making CMake aware of the file and creating
the new target with the following commands. You can check the actual config
here
# Specify second test program and source files
set(test2 Test2Tester)
set(test2src lib-tester2.cpp)
# Specify executable for second tester
add_executable(${test2} ${test2src})
# Specify target for second test program
target_link_libraries( ${test2} LINK_PUBLIC ${GTEST_LIBRARIES} ${CMAKE_PROJECT_NAME})
Telling Xcode about the changes.
For this we simply need to rerun cmake with the same command we used to generate the Xcode project.
Here I am running the command from build-xcode
cmake .. -GXcode
Cmake will update the project files and xcode should show the following changes. These changes are marked with small red circles. There should be three of them.
Running the new Test Program.
Just select test2Tester as the new target at the top of the editor as shown in the image above and running the target.
This will give you the following:
If you look closely you will see that we are now running Test1.Number
which is
different to our previous test program which was mTESTThree.Number
Closing Comment
I put this together just to show that using CMake can help us have a consistent code base while developers might use different IDEs.