Day 2 : 9 June 2022 : Introducing CMake
My 100 Daze of Code
https://github.com/davidjwalling/100-days-of-code
Introducing CMake
In our previous examples, we used a traditional Makefile to build project Ava on Linux. Here, we'll introduce using CMake, an arguably more modern and powerful build technology. We'll also demonstrate using the CMake scripts to build Ava on Linux and macOS.
Ordinarily, we would try to maintain backward compatibility with an older build method to allow flexibility and choice. Here, though, we will stop using a manually maintained Makefile because there is no target platform in our scope that can't be maintained using CMake. Also, CMake projects typically make use of an hierarchical folder organization that can lead to challenges with Makefile. Among the many advantages that CMake brings is its implicit determination of dependencies, which is explicitly defined in Makefile.
We'll still use CMake to generate a Makefile, at least at this stage. But we don't have to manually maintain Make file anymore.
CMake Folder Hierarchy
CMake supports organizing source code into folders that can help compartmentalize each project's scope. Here, we will have one top-level CMakeLists.txt file that will reference two others, once for the Ava library (libava) and one for the Ava executable (ava). The Makefile file from our previous example is removed. No changes are required to our program source code (.cpp, .h).
+--- ava ------------+--- CMakeLists.txt
+--- main.cpp
+--- libava ---------+--- CMakeLists.txt
+--- api.h
+--- driver.cpp
+--- driver.h
Adding a .gitignore File
CMake Scripts
src/libava/CMakeLists.txt
Here we create a CMakeLists.txt file for the library. Some features will be relevant to Windows when we introduce support for that operating system.
1. Add the _WINDLL definition if building with the Microsoft Visual C++ compiler.
2. Define the library source modules and public API headers.
3. Indicate the library will generate position-independent code.
4. Define the location where headers will be found during build and install phases.
5. Define the location where artifacts will be located in the package.
6. Include Ava's CMake and Windows Debug .pdb files in the package artifact.
src/ava/CMakeLists.txt
Here we create a CMakeLists.txt file for the executable.
1. Specify the source modules for the executable.
2. The executable requires only that the libava library is linked.
3. Specify the installation folder for the executable.
src/CMakeLists.txt
Here, we create the CMake script for the overall project. Some definitions are specific to Windows, which we'll cover later.
1. Provide a default build number (99) if none is found.
2. Apply the build number to the build version.
3. Define the package vendor and patch. Note that CPack assumes a three-part version (major, minor, patch). So here, we defined the package version with a patch that is the patch and version, concatenated.
4. Define usual and customary installation folders (bin, lib).
5. Set the C++ compatibility version to inform the compiler.
6. Provide platform-specific compiler options. Note that setting "visibility=hidden" for Clang or GNU will require explicitly making library entry points visible (see api.h and driver.h examples).
7. Indicate the subfolders to include in the build.
Build and Run
Linux
1. Create /src/build and change directory into it. We'll run our build in the build folder so that it does not add files in our source folder that would have to be selectively cleaned up later.
2. Run CMake in /src/build, pointing to the parent. This step generates a Makefile and other dependencies.
3. Run "make" to compile our library and executable using the Makefile generated in step 2.
4. Run "sudo make install" to install our library and executable.
5. Run "ava" to demonstrate locating, loading and running the executable and dynamically loading and running the library.
Here, we'll stage, commit and push our changes to Git and then clone the repository in macOS.
macOS
1. Clone the updated repo locally on macOS.
2. Create /src/build and change directory into it. We'll run our build in the build folder so that it does not add files in our source folder that would have to be selectively cleaned up later.
3. Run CMake in /src/build, pointing to the parent. This step generates a Makefile and other dependencies.
4. Run "make" to compile our library and executable using the Makefile generated in step 2.
5. Run "sudo make install" to install our library and executable.
6. Run "ava" to demonstrate locating, loading and running the executable and dynamically loading and running the library.
Comments
Post a Comment