mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-23 15:38:52 -06:00
Tutorial: Add Step 1 background info and update style
This commit is contained in:
@@ -1,45 +1,81 @@
|
||||
Step 1: A Basic Starting Point
|
||||
==============================
|
||||
|
||||
The most basic project is an executable built from source code files.
|
||||
For simple projects, a three line ``CMakeLists.txt`` file is all that is
|
||||
required. This will be the starting point for our tutorial. Create a
|
||||
``CMakeLists.txt`` file in the ``Step1`` directory that looks like:
|
||||
Where do I start with CMake? This step will provide an introduction to some of
|
||||
CMake's basic syntax, commands, and variables. As these concepts are
|
||||
introduced, we will work through three exercises and create a simple CMake
|
||||
project.
|
||||
|
||||
.. code-block:: cmake
|
||||
:caption: CMakeLists.txt
|
||||
:name: CMakeLists.txt-start
|
||||
Each exercise in this step will start with some background information. Then, a
|
||||
goal and list of helpful resources are provided. Each file in the
|
||||
``Files to Edit`` section is in the ``Step1`` directory and contains one or
|
||||
more ``TODO`` comments. Each ``TODO`` represents a line or two of code to
|
||||
change or add. The ``TODO`` s are intended to be completed in numerical order,
|
||||
first complete ``TODO 1`` then ``TODO 2``, etc. The ``Getting Started``
|
||||
section will give some helpful hints and guide you through the exercise. Then
|
||||
the ``Build and Run`` section will walk step-by-step through how to build and
|
||||
test the exercise. Finally, at the end of each exercise the intended solution
|
||||
is discussed.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
Also note that each step in the tutorial builds on the next. So, for example,
|
||||
the starting code for ``Step2`` is the complete solution to ``Step1``.
|
||||
|
||||
# set the project name
|
||||
project(Tutorial)
|
||||
Exercise 1 - Building a Basic Project
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
# add the executable
|
||||
add_executable(Tutorial tutorial.cxx)
|
||||
The most basic CMake project is an executable built from a single source code
|
||||
file. For simple projects like this, a ``CMakeLists.txt`` file with three
|
||||
commands is all that is required.
|
||||
|
||||
**Note:** Although upper, lower and mixed case commands are supported by CMake,
|
||||
lower case commands are preferred and will be used throughout the tutorial.
|
||||
|
||||
Any project's top most ``CMakeLists.txt`` must start by specifying
|
||||
a minimum CMake version using :command:`cmake_minimum_required`. This ensures
|
||||
that the later CMake functions are run with a compatible version of CMake.
|
||||
Any project's top most CMakeLists.txt must start by specifying a minimum CMake
|
||||
version using the :command:`cmake_minimum_required` command. This establishes
|
||||
policy settings and ensures that the following CMake functions are run with a
|
||||
compatible version of CMake.
|
||||
|
||||
To start a project, we use :command:`project` to set the project name. This
|
||||
call is required with every project and should be called soon after
|
||||
:command:`cmake_minimum_required`.
|
||||
To start a project, we use the :command:`project` command to set the project
|
||||
name. This call is required with every project and should be called soon after
|
||||
:command:`cmake_minimum_required`. As we will see later, this command can
|
||||
also be used to specify other project level information such as the language
|
||||
or version number.
|
||||
|
||||
Lastly, we use :command:`add_executable` to specify we want an executable
|
||||
named Tutorial generated using ``tutorial.cxx`` as the source.
|
||||
Finally, the :command:`add_executable` command tells CMake to create an
|
||||
executable using the specified source code files.
|
||||
|
||||
Note that this example uses lower case commands in the ``CMakeLists.txt``
|
||||
file. Upper, lower, and mixed case commands are supported by CMake. The source
|
||||
code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be
|
||||
used to compute the square root of a number.
|
||||
Goal
|
||||
----
|
||||
|
||||
Understand how to create a simple CMake project.
|
||||
|
||||
Helpful Resources
|
||||
-----------------
|
||||
|
||||
* :command:`add_executable`
|
||||
* :command:`cmake_minimum_required`
|
||||
* :command:`project`
|
||||
|
||||
Files to Edit
|
||||
-------------
|
||||
|
||||
* ``CMakeLists.txt``
|
||||
|
||||
Getting Started
|
||||
----------------
|
||||
|
||||
The source code for ``tutorial.cxx`` is provided in the
|
||||
``Help/guide/tutorial/Step1`` directory and can be used to compute the square
|
||||
root of a number. This file does not need to be edited in this step.
|
||||
|
||||
In the same directory is a ``CMakeLists.txt`` file which you will complete.
|
||||
Start with ``TODO 1`` and work through ``TODO 3``.
|
||||
|
||||
Build and Run
|
||||
-------------
|
||||
|
||||
That's all that is needed - we can build and run our project now! First, run
|
||||
the :manual:`cmake <cmake(1)>` executable or the
|
||||
Once ``TODO 1`` through ``TODO 3`` have been completed, we are ready to build
|
||||
and run our project! First, run the :manual:`cmake <cmake(1)>` executable or the
|
||||
:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
|
||||
with your chosen build tool.
|
||||
|
||||
@@ -51,8 +87,9 @@ build directory:
|
||||
|
||||
mkdir Step1_build
|
||||
|
||||
Next, navigate to the build directory and run CMake to configure the project
|
||||
and generate a native build system:
|
||||
Next, navigate to that build directory and run
|
||||
:manual:`cmake <cmake(1)>` to configure the project and generate a native build
|
||||
system:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@@ -73,109 +110,90 @@ Finally, try to use the newly built ``Tutorial`` with these commands:
|
||||
Tutorial 10
|
||||
Tutorial
|
||||
|
||||
Solution
|
||||
--------
|
||||
|
||||
Adding a Version Number and Configured Header File
|
||||
--------------------------------------------------
|
||||
|
||||
The first feature we will add is to provide our executable and project with a
|
||||
version number. While we could do this exclusively in the source code, using
|
||||
``CMakeLists.txt`` provides more flexibility.
|
||||
|
||||
First, modify the ``CMakeLists.txt`` file to use the :command:`project` command
|
||||
to set the project name and version number.
|
||||
As mentioned above, a three line ``CMakeLists.txt`` is all that we need to get
|
||||
up and running. The first line is to use :command:`cmake_minimum_required` to
|
||||
set the CMake version as follows:
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: CMakeLists.txt
|
||||
:name: CMakeLists.txt-project-VERSION
|
||||
:caption: TODO 1: CMakeLists.txt
|
||||
:name: CMakeLists.txt-cmake_minimum_required
|
||||
:language: cmake
|
||||
:end-before: # specify the C++ standard
|
||||
:end-before: # set the project name and version
|
||||
|
||||
Then use :command:`configure_file` to pass the version number to the source
|
||||
code:
|
||||
The next step to make a basic project is to use the :command:`project`
|
||||
command as follows to set the project name:
|
||||
|
||||
.. code-block:: cmake
|
||||
:caption: TODO 2: CMakeLists.txt
|
||||
:name: CMakeLists.txt-project
|
||||
|
||||
project(Tutorial)
|
||||
|
||||
|
||||
The last command to call for a basic project is
|
||||
:command:`add_executable`. We call it as follows:
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: CMakeLists.txt
|
||||
:name: CMakeLists.txt-configure_file
|
||||
:caption: TODO 3: CMakeLists.txt
|
||||
:name: CMakeLists.txt-add_executable
|
||||
:language: cmake
|
||||
:start-after: # to the source code
|
||||
:end-before: # add the executable
|
||||
:start-after: # add the executable
|
||||
:end-before: # add the binary tree to the search path for include files
|
||||
|
||||
Since the configured file will be written into the binary tree, we
|
||||
must add that directory to the list of paths to search for include
|
||||
files. Use :command:`target_include_directories` to add the following lines to
|
||||
the end of the ``CMakeLists.txt`` file:
|
||||
Exercise 2 - Specifying the C++ Standard
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: CMakeLists.txt
|
||||
:name: CMakeLists.txt-target_include_directories
|
||||
:language: cmake
|
||||
:start-after: # so that we will find TutorialConfig.h
|
||||
CMake has some special variables that are either created behind the scenes or
|
||||
have meaning to CMake when set by project code. Many of these variables start
|
||||
with ``CMAKE_``. Avoid this naming convention when creating variables for your
|
||||
projects. Two of these special user settable variables are
|
||||
:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`.
|
||||
These may be used together to specify the C++ standard needed to build the
|
||||
project.
|
||||
|
||||
Using your favorite editor, create ``TutorialConfig.h.in`` in the source
|
||||
directory with the following contents:
|
||||
Goal
|
||||
----
|
||||
|
||||
.. literalinclude:: Step2/TutorialConfig.h.in
|
||||
:caption: TutorialConfig.h.in
|
||||
:name: TutorialConfig.h.in
|
||||
:language: c++
|
||||
Add a feature that requires C++11.
|
||||
|
||||
When CMake configures this header file, the values for
|
||||
``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be
|
||||
replaced with the corresponding version numbers from the project.
|
||||
Helpful Resources
|
||||
-----------------
|
||||
|
||||
Next modify ``tutorial.cxx`` to include the configured header file,
|
||||
``TutorialConfig.h``.
|
||||
* :variable:`CMAKE_CXX_STANDARD`
|
||||
* :variable:`CMAKE_CXX_STANDARD_REQUIRED`
|
||||
* :command:`set`
|
||||
|
||||
Finally, let's print out the executable name and version number by updating
|
||||
``tutorial.cxx`` as follows:
|
||||
Files to Edit
|
||||
-------------
|
||||
|
||||
.. literalinclude:: Step2/tutorial.cxx
|
||||
:caption: tutorial.cxx
|
||||
:name: tutorial.cxx-print-version
|
||||
:language: c++
|
||||
:start-after: {
|
||||
:end-before: // convert input to double
|
||||
* ``CMakeLists.txt``
|
||||
* ``tutorial.cxx``
|
||||
|
||||
Specify the C++ Standard
|
||||
-------------------------
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Next let's add some C++11 features to our project by replacing ``atof`` with
|
||||
``std::stod`` in ``tutorial.cxx``. At the same time, remove
|
||||
``#include <cstdlib>``.
|
||||
Continue editing files in the ``Step1`` directory. Start with ``TODO 4`` and
|
||||
complete through ``TODO 6``.
|
||||
|
||||
.. literalinclude:: Step2/tutorial.cxx
|
||||
:caption: tutorial.cxx
|
||||
:name: tutorial.cxx-cxx11
|
||||
:language: c++
|
||||
:start-after: // convert input to double
|
||||
:end-before: // calculate square root
|
||||
First, edit ``tutorial.cxx`` by adding a feature that requires C++11. Then
|
||||
update ``CMakeLists.txt`` to require C++11.
|
||||
|
||||
We will need to explicitly state in the CMake code that it should use the
|
||||
correct flags. The easiest way to enable support for a specific C++ standard
|
||||
in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this
|
||||
tutorial, :command:`set` the :variable:`CMAKE_CXX_STANDARD` variable in the
|
||||
``CMakeLists.txt`` file to ``11`` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`
|
||||
to ``True``. Make sure to add the ``CMAKE_CXX_STANDARD`` declarations above the
|
||||
call to ``add_executable``.
|
||||
Build and Run
|
||||
-------------
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: CMakeLists.txt
|
||||
:name: CMakeLists.txt-CXX_STANDARD
|
||||
:language: cmake
|
||||
:end-before: # configure a header file to pass some of the CMake settings
|
||||
|
||||
Rebuild
|
||||
-------
|
||||
|
||||
Let's build our project again. We already created a build directory and ran
|
||||
CMake, so we can skip to the build step:
|
||||
Let's build our project again. Since we already created a build directory and
|
||||
ran CMake for Exercise 1, we can skip to the build step:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cd Step1_build
|
||||
cmake --build .
|
||||
|
||||
Now we can try to use the newly built ``Tutorial`` with same commands as before:
|
||||
Now we can try to use the newly built ``Tutorial`` with same commands as
|
||||
before:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@@ -183,5 +201,173 @@ Now we can try to use the newly built ``Tutorial`` with same commands as before:
|
||||
Tutorial 10
|
||||
Tutorial
|
||||
|
||||
Check that the version number is now reported when running the executable without
|
||||
any arguments.
|
||||
Solution
|
||||
--------
|
||||
|
||||
We start by adding some C++11 features to our project by replacing
|
||||
``atof`` with ``std::stod`` in ``tutorial.cxx``. This looks like
|
||||
the following:
|
||||
|
||||
.. literalinclude:: Step2/tutorial.cxx
|
||||
:caption: TODO 4: tutorial.cxx
|
||||
:name: tutorial.cxx-cxx11
|
||||
:language: c++
|
||||
:start-after: // convert input to double
|
||||
:end-before: // calculate square root
|
||||
|
||||
To complete ``TODO 5``, simply remove ``#include <cstdlib>``.
|
||||
|
||||
We will need to explicitly state in the CMake code that it should use the
|
||||
correct flags. One way to enable support for a specific C++ standard in CMake
|
||||
is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this tutorial, set
|
||||
the :variable:`CMAKE_CXX_STANDARD` variable in the ``CMakeLists.txt`` file to
|
||||
``11`` and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to ``True``. Make sure to
|
||||
add the :variable:`CMAKE_CXX_STANDARD` declarations above the call to
|
||||
:command:`add_executable`.
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: TODO 6: CMakeLists.txt
|
||||
:name: CMakeLists.txt-CXX_STANDARD
|
||||
:language: cmake
|
||||
:start-after: # specify the C++ standard
|
||||
:end-before: # configure a header file to pass some of the CMake settings
|
||||
|
||||
Exercise 3 - Adding a Version Number and Configured Header File
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes it may be useful to have a variable that is defined in your
|
||||
``CMakelists.txt`` file also be available in your source code. In this case, we
|
||||
would like to print the project version.
|
||||
|
||||
One way to accomplish this is by using a configured header file. We create an
|
||||
input file with one or more variables to replace. These variables have special
|
||||
syntax which looks like ``@VAR@``.
|
||||
Then, we use the :command:`configure_file` command to copy the input file to a
|
||||
given output file and replace these variables with the current value of ``VAR``
|
||||
in the ``CMakelists.txt`` file.
|
||||
|
||||
While we could edit the version directly in the source code, using this
|
||||
feature is preferred since it creates a single source of truth and avoids
|
||||
duplication.
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
Define and report the project's version number.
|
||||
|
||||
Helpful Resources
|
||||
-----------------
|
||||
|
||||
* :variable:`<PROJECT-NAME>_VERSION_MAJOR`
|
||||
* :variable:`<PROJECT-NAME>_VERSION_MINOR`
|
||||
* :command:`configure_file`
|
||||
* :command:`target_include_directories`
|
||||
|
||||
Files to Edit
|
||||
-------------
|
||||
|
||||
* ``CMakeLists.txt``
|
||||
* ``tutorial.cxx``
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Continue to edit files from ``Step1``. Start on ``TODO 7`` and complete through
|
||||
``TODO 12``. In this exercise, we start by adding a project version number in
|
||||
``CMakeLists.txt``. In that same file, use :command:`configure_file` to copy a
|
||||
given input file to an output file and substitute some variable values in the
|
||||
input file content.
|
||||
|
||||
Next, create an input header file ``TutorialConfig.h.in`` defining version
|
||||
numbers which will accept variables passed from :command:`configure_file`.
|
||||
|
||||
Finally, update ``tutorial.cxx`` to print out its version number.
|
||||
|
||||
Build and Run
|
||||
-------------
|
||||
|
||||
Let's build our project again. As before, we already created a build directory
|
||||
and ran CMake so we can skip to the build step:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cd Step1_build
|
||||
cmake --build .
|
||||
|
||||
Verify that the version number is now reported when running the executable
|
||||
without any arguments.
|
||||
|
||||
Solution
|
||||
--------
|
||||
|
||||
In this exercise, we improve our executable by printing a version number.
|
||||
While we could do this exclusively in the source code, using ``CMakeLists.txt``
|
||||
lets us maintain a single source of data for the version number.
|
||||
|
||||
First, we modify the ``CMakeLists.txt`` file to use the
|
||||
:command:`project` command to set both the project name and version number.
|
||||
When the command:`project` command is called, CMake defines
|
||||
``Tutorial_VERSION_MAJOR`` and ``Tutorial_VERSION_MINOR`` behind the scenes.
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: TODO 7: CMakeLists.txt
|
||||
:name: CMakeLists.txt-project-VERSION
|
||||
:language: cmake
|
||||
:start-after: # set the project name and version
|
||||
:end-before: # specify the C++ standard
|
||||
|
||||
Then we used :command:`configure_file` to copy the input file with the
|
||||
specified CMake variables replaced:
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: TODO 8: CMakeLists.txt
|
||||
:name: CMakeLists.txt-configure_file
|
||||
:language: cmake
|
||||
:start-after: # to the source code
|
||||
:end-before: # add the executable
|
||||
|
||||
Since the configured file will be written into the project binary
|
||||
directory, we must add that directory to the list of paths to search for
|
||||
include files.
|
||||
|
||||
**Note:** Throughout this tutorial, we will refer to the project build and
|
||||
the project binary directory interchangeably. These are the same and are not
|
||||
meant to refer to a `bin/` directory.
|
||||
|
||||
We used :command:`target_include_directories` to specify
|
||||
where the executable target should look for include files.
|
||||
|
||||
.. literalinclude:: Step2/CMakeLists.txt
|
||||
:caption: TODO 9: CMakeLists.txt
|
||||
:name: CMakeLists.txt-target_include_directories
|
||||
:language: cmake
|
||||
:start-after: # so that we will find TutorialConfig.h
|
||||
|
||||
``TutorialConfig.h.in`` is the input header file to be configured.
|
||||
When :command:`configure_file` is called from our ``CMakeLists.txt``, the
|
||||
values for ``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will
|
||||
be replaced with the corresponding version numbers from the project in
|
||||
``TutorialConfig.h``.
|
||||
|
||||
.. literalinclude:: Step2/TutorialConfig.h.in
|
||||
:caption: TODO 10: TutorialConfig.h.in
|
||||
:name: TutorialConfig.h.in
|
||||
:language: c++
|
||||
|
||||
Next, we need to modify ``tutorial.cxx`` to include the configured header file,
|
||||
``TutorialConfig.h``.
|
||||
|
||||
.. code-block:: c++
|
||||
:caption: TODO 11: tutorial.cxx
|
||||
|
||||
#include "TutorialConfig.h"
|
||||
|
||||
Finally, we print out the executable name and version number by updating
|
||||
``tutorial.cxx`` as follows:
|
||||
|
||||
.. literalinclude:: Step2/tutorial.cxx
|
||||
:caption: TODO 12 : tutorial.cxx
|
||||
:name: tutorial.cxx-print-version
|
||||
:language: c++
|
||||
:start-after: {
|
||||
:end-before: // convert input to double
|
||||
|
||||
16
Help/guide/tutorial/Step1/CMakeLists.txt
Normal file
16
Help/guide/tutorial/Step1/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# TODO 1: Set the minimum required version of CMake to be 3.10
|
||||
|
||||
# TODO 2: Create a project named Tutorial
|
||||
|
||||
# TODO 7: Set the project version number as 1.0 in the above project command
|
||||
|
||||
# TODO 6: Set the variable CMAKE_CXX_STANDARD to 11
|
||||
# and the variable CMAKE_CXX_REQUIRED_STANDARD to True
|
||||
|
||||
# TODO 8: Use configure_file to configure and copy TutorialConfig.h.in to
|
||||
# TutorialConfig.h
|
||||
|
||||
# TODO 3: Add an executable called Tutorial to the project
|
||||
# Hint: Be sure to specify the source file as tutorial.cxx
|
||||
|
||||
# TODO 9: Use target_include_directories to include ${PROJECT_BINARY_DIR}
|
||||
2
Help/guide/tutorial/Step1/TutorialConfig.h.in
Normal file
2
Help/guide/tutorial/Step1/TutorialConfig.h.in
Normal file
@@ -0,0 +1,2 @@
|
||||
// the configured options and settings for Tutorial
|
||||
// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR
|
||||
@@ -1,17 +1,22 @@
|
||||
// A simple program that computes the square root of a number
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdlib> // TODO 5: Remove this line
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
// TODO 11: Include TutorialConfig.h
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
// TODO 12: Create a print statement using Tutorial_VERSION_MAJOR
|
||||
// and Tutorial_VERSION_MINOR
|
||||
std::cout << "Usage: " << argv[0] << " number" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// convert input to double
|
||||
// TODO 4: Replace atof(argv[1]) with std::stod(argv[1])
|
||||
const double inputValue = atof(argv[1]);
|
||||
|
||||
// calculate square root
|
||||
|
||||
Reference in New Issue
Block a user