CMake Build System: Difference between revisions

m
no edit summary
[unchecked revision][unchecked revision]
(Some copyediting, clarification, and fixes to syntax errors in some code blocks.)
mNo edit summary
Tag: Manual revert
 
(5 intermediate revisions by 3 users not shown)
Line 75:
You can emit messages back to the console using the <code>MESSAGE()</code> command. Note that this is only run at CMake time. You can use this command for debugging your CMake project. Alternately, if you supply <code>STATUS</code> as the first parameter to this command, it will print out a specialized status message for you.
 
<sourcesyntaxhighlight lang="cmake">
# So CMake can tell whether or not it can process this file
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
Line 89:
# Note how we obtain this variable's value!
ADD_EXECUTABLE(foo ${C_SRCS})
</syntaxhighlight>
</source>
 
This is enough for a small project to generate an executable. Creating the associated Makefile and starting the build is simple:
Line 109:
A common approach involves generating custom build scripts for each sub-project you create. Thus, we have a separate CMakeLists.txt for each sub-project we create, and we link them together in the CMakeLists.txt in the project root. If we adhere to our filesystem layout from above, for instance, we'd have 3 CMakeLists.txt files: one in /, one in /src/kernel, and one in /src/libc. We can link them together with the following:
 
<sourcesyntaxhighlight lang="cmake">
ADD_SUBDIRECTORY(src/kernel)
ADD_SUBDIRECTORY(src/libc)
</syntaxhighlight>
</source>
 
Using the <code>ADD_SUBDIRECTORY()</code> command is analagous to recursively calling make, and in many cases, this is precisely what happens. Other generators may interpret this command differently: for instance, the MSVC generator might decide to turn these directories into multiple projects within a solution. In either case, the child CMakeLists.txt inherits the environment of the parent so variables are propagated. You can use this to your advantage by doing dependency resolution and setting up critical shared variables in the root CMakeLists.txt file.
Line 127:
Unless you intend to use somebody else's kernel and write your operating system completely from portable code, it is very likely that you will need an assembler. For the kinds of projects that CMake was designed for, this rarely comes up; as an operating system designer, such support is probably critical to your project. Fortunately, some work has been done to address this issue and in most cases you can get away with not only detecting an assembler, but even specifying the syntax it uses. By using the <code>ENABLE_LANGUAGE()</code> command it is possible to turn on support for assembly:
 
<sourcesyntaxhighlight lang="cmake">
# We want an AT&T Syntax Assembler
ENABLE_LANGUAGE(ASM-ATT)
 
ADD_EXECUTABLE(foo bar.s baz.s)
</syntaxhighlight>
</source>
 
=== Setting Appropriate Build Options ===
Line 167:
However, there is a slight problem: we need a way to report our findings to the caller. Remember that variables defined in functions go out of scope as soon as the function ends. We could use a macro here at the risk of polluting the namespace but it would be much better if we could export variables to the parent scope. Fortunately, the <code>SET()</code> command accepts <code>PARENT_SCOPE</code> as an optional parameter. When this is used, it means that the variable being set should become part of the parent's environment. Let's write a small build profile function now:
 
<sourcesyntaxhighlight lang="cmake">
FUNCTION(LOAD_PROFILE ISA PLATFORM)
# Obtain sources for the ISA
Line 187:
# ...
ENDFUNCTION(LOAD_PROFILE)
</syntaxhighlight>
</source>
 
Now, all we have to do is call <code>LOAD_PROFILE()</code> with the provided parameters, and we should be able to set up our build environment in a sane manner:
 
<sourcesyntaxhighlight lang="cmake">
FILE(GLOB GENERIC_SRCS "*.c")
 
Line 206:
SET_TARGET_PROPERTIES(kernel PROPERTIES LINK_FLAGS
"-T ${PLATFORM_LAYOUT} -N ${ISA_LINKER_FLAGS} ${PLATFORM_LINKER_FLAGS}")
</syntaxhighlight>
</source>
 
Here, we make a reasonable attempt to control the build order, but the truth is, we don't really know exactly what that order should be; it might
be dependent on the platform. For instance, for i386/pc, we might want a multiboot header, which must come within the first 8K of the kernel image. In that case, we must somehow control the ordering. We could have a place <code>FIRST_SRCS()</code> variable present in the platform flags, then use the following loop to extract it from the list:
 
<sourcesyntaxhighlight lang="cmake">
FOREACH(I ${FIRST_SRCS})
# Assume path is relative to src/kernel
Line 223:
# During exports:
SET(FIRST_SRCS ${TMP_FIRST_SRCS})
</syntaxhighlight>
</source>
 
Now, all we have to do is put <code>${FIRST_SRCS}</code> at the head of the list, and we can control the order in which our code is linked.
Line 233:
 
=== External Links ===
* [http://www.cmake.org CMake Offical Page] - Contains useful links, including how to download and documentation.
* [http://www.cmake.org/Wiki/CMake_Useful_Variables CMake Useful Variables] - Gives names and descriptions of common and useful variables used in CMake.
* [http://www.cmake.org/cmake/help/v3.2 CMake Official Documentation] - Official documentation all about CMake.
* [http://www.cmake.org/Wiki/CMake/Examples CMake Examples] - Examples showing how to perform many common CMake procedures.
 
[[Category:Build Tools]]
[[Category:Tools]]