-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCMakeBestPractices.html
241 lines (198 loc) · 16.8 KB
/
CMakeBestPractices.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CMake Guidelines</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css?v=fadd4351" />
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=77160d70" />
<script src="_static/documentation_options.js?v=a8da1a53"></script>
<script src="_static/doctools.js?v=9bcbadda"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Standards" href="Standards/index.html" />
<link rel="prev" title="Building with CMake" href="BuildingWithCMake.html" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-59110517-1', 'auto');
ga('send', 'pageview');
</script>
</head><body>
<div id="navbar" class="navbar navbar-default ">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://www.mantidproject.org">
</a>
<span class="navbar-text navbar-version pull-left"><b>main</b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li class="divider-vertical"></li>
<li><a href="index.html">Home</a></li>
<li><a href="https://download.mantidproject.org">Download</a></li>
<li><a href="https://docs.mantidproject.org">User Documentation</a></li>
<li><a href="http://www.mantidproject.org/contact">Contact Us</a></li>
</ul>
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<p>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="nav-item nav-item-0"><a href="index.html">Documentation</a> »</li>
<li class="nav-item nav-item-this"><a href="">CMake Guidelines</a></li>
</ul>
</div> </p>
</div>
<div class="container">
<div class="row">
<div class="body col-md-12 content" role="main">
<section id="cmake-guidelines">
<span id="cmakebestpractices"></span><h1>CMake Guidelines<a class="headerlink" href="#cmake-guidelines" title="Link to this heading">¶</a></h1>
<p>This document outlines a few CMake guidelines which should be considered when modifying Mantid’s CMake code.
A brief introduction to modern CMake can be found at <a class="reference external" href="https://hsf-training.github.io/hsf-training-cmake-webpage/">https://hsf-training.github.io/hsf-training-cmake-webpage/</a>.
The official CMake tutorial series are also very good <a class="reference external" href="https://cmake.org/cmake/help/latest/guide/tutorial/index.html">https://cmake.org/cmake/help/latest/guide/tutorial/index.html</a></p>
</section>
<section id="creating-a-new-cmake-library">
<h1>Creating a new CMake Library<a class="headerlink" href="#creating-a-new-cmake-library" title="Link to this heading">¶</a></h1>
<p>If you are adding a new CMake library, for example to the framework, there are a couple of steps you need to take.
Firstly, lets consider a new framework target <cite>Fitting</cite>, which is a shared library which can be created with:</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">add_library</span><span class="p">(</span><span class="s">Fitting</span><span class="w"> </span><span class="s">fitting.cpp</span><span class="w"> </span><span class="s">fitting_1.cpp</span><span class="w"> </span><span class="s">fitting.h</span><span class="w"> </span><span class="s">fitting_1.h</span><span class="p">)</span>
</pre></div>
</div>
<p>While not required, it is typically good practice to include the headers in the <code class="docutils literal notranslate"><span class="pre">add_library</span></code> call as it helps IDEs such as Visual Studio find the headers associated with the library.</p>
<p>This new target, <code class="docutils literal notranslate"><span class="pre">Fitting</span></code>, will likely have a set of dependencies, these should be included using the <code class="docutils literal notranslate"><span class="pre">target_link_libraries</span></code> function:</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">target_link_libraries</span><span class="p">(</span><span class="s"><target></span>
<span class="w"> </span><span class="s"><PRIVATE|PUBLIC|INTERFACE></span><span class="w"> </span><span class="s"><item>...</span>
<span class="w"> </span><span class="s">[<PRIVATE|PUBLIC|INTERFACE></span><span class="w"> </span><span class="s"><item>...]...</span><span class="p">)</span>
</pre></div>
</div>
<p>Whether or not a dependency is PUBLIC or PRIVATE primarily depends on whether the code has been included in a public header. For example, if we had used Boost’s date_time library in our header files for the Fitting target,
we would add Boost::date_time as a PUBLIC dependency of our target.</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">target_link_libraries</span><span class="p">(</span><span class="s">Fitting</span><span class="w"> </span><span class="s">PUBLIC</span><span class="w"> </span><span class="s">Boost::date_time</span><span class="p">)</span>
</pre></div>
</div>
<p>Otherwise, if Boost date_time was only present in the source files we could add it as a PRIVATE dependency.</p>
<p>The target based linking also includes any <code class="docutils literal notranslate"><span class="pre">INTERFACE_INCLUDE_DIRECTORIES</span></code> of the linked target, i.e. it will naturally include header files with it. This means we do not need to use target_include_directories to include Boost’s headers.</p>
<p>If you find yourself doing something like <code class="docutils literal notranslate"><span class="pre">target_include_directories(Fitting</span> <span class="pre">PUBLIC</span> <span class="pre">${Boost_include_dirs})</span></code> you’ve probably done something wrong. This goes against the modern CMake target approach. The only thing target_include_directories is needed for is
to tell users of your Fitting library where it can find its headers:</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">target_include_directories</span><span class="p">(</span>
<span class="w"> </span><span class="s">Fitting</span><span class="w"> </span><span class="s">PUBLIC</span>
<span class="w"> </span><span class="o">$<</span><span class="nv">BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc</span><span class="o">></span>
<span class="p">)</span>
</pre></div>
</div>
<p>This specifies that while building the project, the headers for fitting can be found in the inc/ subfolder.</p>
<p>Tips:</p>
<blockquote>
<div><ul class="simple">
<li><p>Please use this target based approach. Do not link the CMake target to variables such as <code class="docutils literal notranslate"><span class="pre">${Boost_LIBRARIES}</span></code>.</p></li>
<li><p>Consider whether the dependencies are PUBLIC or PRIVATE. If you wrongly specify things as public it adds unnecessary dependencies to users of your library.</p></li>
<li><p>Please rethink if you are using <code class="docutils literal notranslate"><span class="pre">target_include_directories</span></code> to include headers from an external library, as the <code class="docutils literal notranslate"><span class="pre">target_link_libraries</span></code> should have already resolved those requirements.</p></li>
</ul>
</div></blockquote>
</section>
<section id="finding-a-new-cmake-dependency">
<h1>Finding a new CMake dependency<a class="headerlink" href="#finding-a-new-cmake-dependency" title="Link to this heading">¶</a></h1>
<p>If you are adding a new CMake dependency you’ll need to find it using the find_package(…) CMake functions. This looks for the library using two mechanisms:</p>
<ol class="arabic simple">
<li><p>Uses Find(…).cmake either from the CMake inbuilt modules, or using our own ones in the buildconfig/CMake folder.</p></li>
<li><p>Uses CMake config files which are optionally installed with the library.</p></li>
</ol>
<p>If neither are working, you’ll likely need to create your own <code class="docutils literal notranslate"><span class="pre">Find(...).cmake</span></code> file. Examples of this include our own <code class="docutils literal notranslate"><span class="pre">FindJsoncpp.cmake</span></code> and <code class="docutils literal notranslate"><span class="pre">FindPoco.cmake</span></code> files. The primary steps in this file are:</p>
<ol class="arabic simple">
<li><p>Use find_library(MY_LIBRARY NAMES name_of_my_library) to search CMake paths for <code class="docutils literal notranslate"><span class="pre">name_of_my_library</span></code></p></li>
<li><p>Use find_path(MY_LIBRARY_INCLUDE_DIR header.h)</p></li>
<li><p>Finally you should create CMake targets based on these libraries using the IMPORTED specifier.</p></li>
</ol>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">add_library</span><span class="p">(</span><span class="s">MyLibrary::mylibrary</span><span class="w"> </span><span class="s">UNKNOWN</span><span class="w"> </span><span class="s">IMPORTED</span><span class="p">)</span>
<span class="nb">set_target_properties</span><span class="p">(</span>
<span class="w"> </span><span class="s">MyLibrary::mylibrary</span>
<span class="w"> </span><span class="s">PROPERTIES</span><span class="w"> </span><span class="s">IMPORTED_LOCATION</span><span class="w"> </span><span class="s2">"${MY_LIBRARY NAMES}"</span>
<span class="w"> </span><span class="s">INTERFACE_INCLUDE_DIRECTORIES</span><span class="w"> </span><span class="s2">"${MY_LIBRARY_INCLUDE_DIR}"</span>
<span class="w"> </span><span class="s">IMPORTED_LINK_INTERFACE_LANGUAGES</span><span class="w"> </span><span class="s2">"CXX"</span>
<span class="p">)</span>
</pre></div>
</div>
<p>After you’ve created this file, you can find mylibrary and its target <code class="docutils literal notranslate"><span class="pre">MyLibrary::mylibrary</span></code> using:</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">find_package</span><span class="p">(</span><span class="s">MyLibrary</span><span class="w"> </span><span class="s">REQUIRED</span><span class="p">)</span>
</pre></div>
</div>
<p>NOTE: The <code class="docutils literal notranslate"><span class="pre">UNKNOWN</span></code> specifier in add_library is useful on Windows as it means we aren’t required to point it to the .lib export libraries. The find_library CMake function will not find these. Usage of Unknown is common place in CMake finders because of this.</p>
</section>
<section id="introducing-a-new-cmake-configurable-variable">
<h1>Introducing a new CMake configurable variable<a class="headerlink" href="#introducing-a-new-cmake-configurable-variable" title="Link to this heading">¶</a></h1>
<p>If you are introducing a new configuration variable for CMake, e.g to conditionally add a new feature, PLEASE cache the variable. If you don’t cache it, you won’t be able to set it on the command line. Example:</p>
<p>If you add a new feature and control it with a flag</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span><span class="p">(</span><span class="s">MY_NEW_FEATURE</span><span class="w"> </span><span class="s">OFF</span><span class="p">)</span>
</pre></div>
</div>
<p>The only way you can change it to ON is to edit it within CMake. If you cache the variable you can set it on the command line</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span><span class="p">(</span><span class="s">MY_NEW_FEATURE</span><span class="w"> </span><span class="s">OFF</span><span class="w"> </span><span class="s">CACHE</span><span class="w"> </span><span class="s">BOOL</span><span class="w"> </span><span class="s2">"Use my new feature"</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-sh notranslate"><div class="highlight"><pre><span></span>cmake<span class="w"> </span>..<span class="w"> </span>-DMY_NEW_FEATURE<span class="o">=</span>ON
</pre></div>
</div>
</section>
<section id="cmake-framework-exports">
<h1>CMake framework exports<a class="headerlink" href="#cmake-framework-exports" title="Link to this heading">¶</a></h1>
<p>With the move to conda, we have created a CMake export target for the Framework libraries. If you add a new Framework library, or dependency there are a couple of things you need to consider.</p>
<ol class="arabic simple">
<li><p>When you add a new Framework library, alias it using the namespace Mantid:: - This means when we link to Mantid::NewTarget it can either link to our inbuilt library, or one on our system. This ensures we can have a standalone mantidqt build.</p></li>
</ol>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">add_library</span><span class="p">(</span><span class="s">NewTarget</span><span class="w"> </span><span class="o">${</span><span class="nv">SRC_FILES</span><span class="o">}</span><span class="w"> </span><span class="o">${</span><span class="nv">INC_FILES</span><span class="o">}</span><span class="p">)</span>
<span class="nb">add_library</span><span class="p">(</span><span class="s">Mantid::NewTarget</span><span class="w"> </span><span class="s">ALIAS</span><span class="w"> </span><span class="s">NewTarget</span><span class="p">)</span>
</pre></div>
</div>
<ol class="arabic simple" start="2">
<li><p>Add the install commands which ensures the target is exported.</p></li>
</ol>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span><span class="p">(</span><span class="s">TARGET_EXPORT_NAME</span><span class="w"> </span><span class="s2">"MantidNewTargetTargets"</span><span class="p">)</span>
<span class="nb">mtd_install_framework_lib</span><span class="p">(</span><span class="s">TARGETS</span><span class="w"> </span><span class="s">NewTarget</span><span class="w"> </span><span class="s">EXPORT_NAME</span><span class="w"> </span><span class="o">${</span><span class="nv">TARGET_EXPORT_NAME</span><span class="o">}</span><span class="p">)</span>
</pre></div>
</div>
<ol class="arabic simple" start="3">
<li><p>Add the new target to the MODULES variable in <code class="docutils literal notranslate"><span class="pre">MantidFrameworkConfig.cmake.in</span></code>. If it added new dependencies also add the relevant <code class="docutils literal notranslate"><span class="pre">find_dependency</span></code> calls.</p></li>
</ol>
</section>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<ul class="nav navbar-nav" style=" float: right;">
<li>
<a href="BuildingWithCMake.html" title="Previous Chapter: Building with CMake"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">« Building with CMake</span>
</a>
</li>
<li>
<a href="Standards/index.html" title="Next Chapter: Standards"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Standards »</span>
</a>
</li>
<li><a href="#">Back to top</a></li>
</ul>
<p>
</p>
</div>
</footer>
</body>
</html>