-
Notifications
You must be signed in to change notification settings - Fork 4
/
Creating-OSX-packages.html
381 lines (343 loc) · 15.1 KB
/
Creating-OSX-packages.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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
<!DOCTYPE html>
<html lang="en">
<head>
<base href=".">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Creating OSX packages</title>
<link rel="stylesheet" href="assets/css/dark-frontend.css" type="text/css" title="dark">
<link rel="alternate stylesheet" href="assets/css/light-frontend.css" type="text/css" title="light">
<link rel="stylesheet" href="assets/css/bootstrap-toc.min.css" type="text/css">
<link rel="stylesheet" href="assets/css/jquery.mCustomScrollbar.min.css">
<link rel="stylesheet" href="assets/js/search/enable_search.css" type="text/css">
<link rel="stylesheet" href="assets/css/prism-tomorrow.css" type="text/css" title="dark">
<link rel="alternate stylesheet" href="assets/css/prism.css" type="text/css" title="light">
<script src="assets/js/mustache.min.js"></script>
<script src="assets/js/jquery.js"></script>
<script src="assets/js/bootstrap.js"></script>
<script src="assets/js/scrollspy.js"></script>
<script src="assets/js/typeahead.jquery.min.js"></script>
<script src="assets/js/search.js"></script>
<script src="assets/js/compare-versions.js"></script>
<script src="assets/js/jquery.mCustomScrollbar.concat.min.js"></script>
<script src="assets/js/bootstrap-toc.min.js"></script>
<script src="assets/js/jquery.touchSwipe.min.js"></script>
<script src="assets/js/anchor.min.js"></script>
<script src="assets/js/tag_filtering.js"></script>
<script src="assets/js/language_switching.js"></script>
<script src="assets/js/styleswitcher.js"></script>
<script src="assets/js/lines_around_headings.js"></script>
<script src="assets/js/prism-core.js"></script>
<script src="assets/js/prism-autoloader.js"></script>
<script src="assets/js/prism_autoloader_path_override.js"></script>
<script src="assets/js/prism-keep-markup.js"></script>
<script src="assets/js/trie.js"></script>
<link rel="icon" type="image/png" href="assets/images/favicon.png">
<link rel="shortcut icon" href="assets/images/favicon.png">
</head>
<body class="no-script
">
<script>
$('body').removeClass('no-script');
</script>
<nav class="navbar navbar-fixed-top navbar-default" id="topnav">
<div class="container-fluid">
<div class="navbar-right">
<a id="toc-toggle">
<span class="glyphicon glyphicon-menu-right"></span>
<span class="glyphicon glyphicon-menu-left"></span>
</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-wrapper" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<span title="light mode switch" class="glyphicon glyphicon-sunglasses pull-right" id="lightmode-icon"></span>
<form class="navbar-form pull-right" id="navbar-search-form">
<div class="form-group has-feedback">
<input type="text" class="form-control input-sm" name="search" id="sidenav-lookup-field" placeholder="search" disabled>
<span class="glyphicon glyphicon-search form-control-feedback" id="search-mgn-glass"></span>
</div>
</form>
</div>
<div class="navbar-header">
<a id="sidenav-toggle">
<span class="glyphicon glyphicon-menu-right"></span>
<span class="glyphicon glyphicon-menu-left"></span>
</a>
<a id="home-link" href="index.html" class="hotdoc-navbar-brand">
<img src="assets/images/meson_logo.png" alt="Home">
</a>
</div>
<div class="navbar-collapse collapse" id="navbar-wrapper">
<ul class="nav navbar-nav" id="menu">
<li class="dropdown">
<a class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Modules <span class="caret"></span>
</a>
<ul class="dropdown-menu" id="modules-menu">
<li>
<a href="CMake-module.html">CMake</a>
</li>
<li>
<a href="Cuda-module.html">CUDA</a>
</li>
<li>
<a href="Dlang-module.html">Dlang</a>
</li>
<li>
<a href="External-Project-module.html">External Project</a>
</li>
<li>
<a href="Fs-module.html">Filesystem</a>
</li>
<li>
<a href="Gnome-module.html">GNOME</a>
</li>
<li>
<a href="Hotdoc-module.html">Hotdoc</a>
</li>
<li>
<a href="i18n-module.html">i18n</a>
</li>
<li>
<a href="Icestorm-module.html">Icestorm</a>
</li>
<li>
<a href="Java-module.html">Java</a>
</li>
<li>
<a href="Keyval-module.html">Keyval</a>
</li>
<li>
<a href="Pkgconfig-module.html">Pkgconfig</a>
</li>
<li>
<a href="Python-3-module.html">Python 3</a>
</li>
<li>
<a href="Python-module.html">Python</a>
</li>
<li>
<a href="Qt4-module.html">Qt4</a>
</li>
<li>
<a href="Qt5-module.html">Qt5</a>
</li>
<li>
<a href="Qt6-module.html">Qt6</a>
</li>
<li>
<a href="Rust-module.html">Rust</a>
</li>
<li>
<a href="Simd-module.html">Simd</a>
</li>
<li>
<a href="SourceSet-module.html">SourceSet</a>
</li>
<li>
<a href="Wayland-module.html">Wayland</a>
</li>
<li>
<a href="Windows-module.html">Windows</a>
</li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Quick References <span class="caret"></span>
</a>
<ul class="dropdown-menu" id="quick-refs-menu">
<li>
<a href="Reference-manual.html">Functions</a>
</li>
<li>
<a href="Build-options.html">Options</a>
</li>
<li>
<a href="Configuration.html">Configuration</a>
</li>
<li>
<a href="Dependencies.html">Dependencies</a>
</li>
<li>
<a href="Unit-tests.html">Tests</a>
</li>
<li>
<a href="Syntax.html">Syntax</a>
</li>
</ul>
</li>
</ul>
<div class="hidden-xs hidden-sm navbar-text navbar-center">
<p><b>The Meson Build System</b></p>
</div>
</div>
</div>
</nav>
<main>
<div data-extension="core" data-hotdoc-in-toplevel="True" data-hotdoc-project="Meson-documentation" data-hotdoc-ref="Creating-OSX-packages.html" class="page_container" id="page-wrapper">
<script src="assets/js/utils.js"></script>
<div class="panel panel-collapse oc-collapsed" id="sidenav" data-hotdoc-role="navigation">
<script src="assets/js/full-width.js"></script>
<div id="sitenav-wrapper">
<iframe src="hotdoc-sitemap.html" id="sitenav-frame"></iframe>
</div>
</div>
<div id="body">
<div id="main">
<div id="page-description" data-hotdoc-role="main">
<h1 id="creating-osx-packages">Creating OSX packages</h1>
<p>Meson does not have native support for building OSX packages but it
does provide all the tools you need to create one yourself. The reason
for this is that it is a very hard task to write a system that
provides for all the different ways to do that but it is very easy to
write simple scripts for each application.</p>
<p>Sample code for this can be found in <a href="https://github.com/jpakkane/meson/tree/master/manual%20tests/4%20standalone%20binaries">the Meson manual test
suite</a>.</p>
<h2 id="creating-an-app-bundle">Creating an app bundle</h2>
<p>OSX app bundles are actually extremely simple. They are just a
directory of files in a certain format. All the details you need to
know are on <a href="https://stackoverflow.com/questions/1596945/building-osx-app-bundle">this
page</a>
and it is highly recommended that you read it first.</p>
<p>Let's assume that we are creating our app bundle into
<code>/tmp/myapp.app</code>. Suppose we have one executable, so we need to
install that into <code>Contents/MacOS</code>. If we define the executable like
this:</p>
<pre><code class="language-meson">executable('myapp', 'foo1.c', ..., install : true)
</code></pre>
<p>then we just need to initialize our build tree with this command:</p>
<pre><code class="language-console">$ meson --prefix=/tmp/myapp.app \
--bindir=Contents/MacOS \
builddir \
<other flags you might need>
</code></pre>
<p>Now when we do <code>meson install</code> the bundle is properly staged. If you
have any resource files or data, you need to install them into
<code>Contents/Resources</code> either by custom install commands or specifying
more install paths to the Meson command.</p>
<p>Next we need to install an <code>Info.plist</code> file and an icon. For those we
need the following two Meson definitions.</p>
<pre><code class="language-meson">install_data('myapp.icns', install_dir : 'Contents/Resources')
install_data('Info.plist', install_dir : 'Contents')
</code></pre>
<p>The format of <code>Info.plist</code> can be found in the link or the sample
project linked above. The simplest way to get an icon in the <code>icns</code>
format is to save your image as a tiff an then use the <code>tiff2icns</code> helper
application that comes with XCode.</p>
<p>Some applications assume that the working directory of the app process
is the same where the binary executable is. If this is the case for
you, then you need to create a wrapper script that looks like this:</p>
<pre><code class="language-bash">#!/bin/bash
cd "${0%/*}"
./myapp
</code></pre>
<p>install it with this:</p>
<pre><code class="language-meson">install_data('myapp.sh', install_dir : 'Contents/MacOS')
</code></pre>
<p>and make sure that you specify <code>myapp.sh</code> as the executable to run in
your <code>Info.plist</code>.</p>
<p>If you are not using any external libraries, this is all you need to
do. You now have a full app bundle in <code>/tmp/myapp.app</code> that you can
use.</p>
<h3 id="external-libraries">External libraries</h3>
<p>Most applications use third party frameworks and libraries.
If it is the case for your project, you need to add them to
the bundle so it will work on other peoples' machines.</p>
<p>As an example we are going to use the <a href="https://libsdl.org/">SDL2</a>
framework. In order to bundle it in our app, we first specify an
installer script to run.</p>
<pre><code class="language-meson"><a href="Reference-manual_builtin_meson.html#mesonadd_install_script"><ins>meson.add_install_script</ins></a>('install_script.sh')
</code></pre>
<p>The install script does two things. First it copies the whole
framework into our bundle.</p>
<pre><code class="language-console">$ mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks
$ cp -R /Library/Frameworks/SDL2.framework \
${MESON_INSTALL_PREFIX}/Contents/Frameworks
</code></pre>
<p>Then it needs to alter the library search path of our
executable(s). This tells OSX that the libraries your app needs are
inside your bundle. In the case of SDL2, the invocation goes like
this:</p>
<pre><code class="language-console">$ install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 \
@executable_path/../FrameWorks/SDL2.framework/Versions/A/SDL2 \
${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp
</code></pre>
<p>This is the part of OSX app bundling that you must always do
manually. OSX dependencies come in many shapes and forms and
unfortunately there is no reliable automatic way to determine how each
dependency should be handled. Frameworks go to the <code>Frameworks</code>
directory while plain <code>.dylib</code> files usually go to
<code>Contents/Resources/lib</code> (but you can put them wherever you like). To
get this done you have to check what your program links against with
<code>otool -L /path/to/binary</code> and manually add the copy and fix steps to
your install script. Do not copy system libraries inside your bundle,
though.</p>
<p>After this you have a fully working, self-contained OSX app bundle
ready for distribution.</p>
<h4 id="qt">Qt</h4>
<p>Qt offers a <a href="https://doc.qt.io/qt-5/macos-deployment.html#macdeploy">deployment tool</a>,
called <code>macdeployqt</code>, that automates bundling Qt's libraries in your application folder and
optionally create the final <code>.dmg</code> installer</p>
<pre><code class="language-console"># cd into the folder that contains the `myapp.app` folder
macdeployqt myapp.app -executable=myapp.app/Contents/MacOS/myapp
</code></pre>
<p>This copies the needed Qt libraries to the correct subfolders within <code>myapp.app</code>.
The <code>-executable=myapp.app/Contents/MacOS/myapp</code> argument is
to automatically alter the search path of the executable
<code>myapp.app/Contents/MacOS/myapp</code> for the Qt libraries. One can also pass the <code>-dmg</code>
argument to create a <code>.dmg</code> installer from the updated <code>myapp.app</code> folder.
More information is available on the tool's documentation page.</p>
<h2 id="creating-a-dmg-installer">Creating a .dmg installer</h2>
<p>A .dmg installer is similarly quite simple, at its core it is
basically a fancy compressed archive. A good description can be found
on <a href="https://el-tramo.be/guides/fancy-dmg/">this page</a>. Please read it
and create a template image file according to its instructions.</p>
<p>The actual process of creating the installer is very simple: you mount
the template image, copy your app bundle in it, unmount it and convert
the image into a compressed archive. The actual commands to do this
are not particularly interesting, feel free to steal them from either
the linked page above or from the sample script in Meson's test suite.</p>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>There are many ways to put the .dmg installer together and different
people will do it in different ways. The linked sample code does it by
having two different scripts. This separates the different pieces
generating the installer into logical pieces.</p>
<p><code>install_script.sh</code> only deals with embedding dependencies and fixing
the library paths.</p>
<p><code>build_osx_installer.sh</code> sets up the build with the proper paths,
compiles, installs and generates the .dmg package.</p>
<p>The main reasoning here is that in order to build a complete OSX
installer package from source, all you need to do is to cd into the
source tree and run <code>./build_osx_installer.sh</code>. To build packages on
other platforms you would write scripts such as
<code>build_windows_installer.bat</code> and so on.</p>
</div>
</div>
<div id="search_results">
<p>The results of the search are</p>
</div>
<div id="footer">
<hr>
<div class="license-description">
Website licensing information are available on the <a href="legal.html">Legal</a> page.
</div>
</div>
</div>
<div id="toc-column">
<div class="edit-button">
<a href="https://github.com/mesonbuild/meson/edit/master/docs/markdown/Creating-OSX-packages.md" data-hotdoc-role="edit-button">Edit on GitHub</a>
</div>
<div id="toc-wrapper">
<nav id="toc"></nav>
</div>
</div>
</div>
</main>
<script src="assets/js/navbar_offset_scroller.js"></script>
</body>
</html>