CPackRPM.cmake 79.1 KB
Newer Older
1
2
3
4
#.rst:
# CPackRPM
# --------
#
5
# The built in (binary) CPack RPM generator (Unix only)
6
#
7
8
9
# Variables specific to CPack RPM generator
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
10
11
12
# CPackRPM may be used to create RPM packages using :module:`CPack`.
# CPackRPM is a :module:`CPack` generator thus it uses the ``CPACK_XXX``
# variables used by :module:`CPack`.
13
#
14
15
# CPackRPM has specific features which are controlled by the specifics
# :code:`CPACK_RPM_XXX` variables.
16
#
17
18
19
# :code:`CPACK_RPM_<COMPONENT>_XXXX` variables may be used in order to have
# **component** specific values.  Note however that ``<COMPONENT>`` refers to the
# **grouping name** written in upper case. It may be either a component name or
20
21
# a component GROUP name. Usually those variables correspond to RPM spec file
# entities. One may find information about spec files here
22
23
24
25
# http://www.rpm.org/wiki/Docs
#
# .. note::
#
26
#  `<COMPONENT>` part of variables is preferred to be in upper case (for e.g. if
27
28
29
30
31
32
33
34
35
36
#  component is named `foo` then use `CPACK_RPM_FOO_XXXX` variable name format)
#  as is with other `CPACK_<COMPONENT>_XXXX` variables.
#  For the purposes of back compatibility (CMake/CPack version 3.5 and lower)
#  support for same cased component (e.g. `fOo` would be used as
#  `CPACK_RPM_fOo_XXXX`) is still supported for variables defined in older
#  versions of CMake/CPack but is not guaranteed for variables that
#  will be added in the future. For the sake of back compatibility same cased
#  component variables also override upper cased versions where both are
#  present.
#
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Here are some CPackRPM wiki resources that are here for historic reasons and
# are no longer maintained but may still prove useful:
#
#  - https://cmake.org/Wiki/CMake:CPackConfiguration
#  - https://cmake.org/Wiki/CMake:CPackPackageGenerators#RPM_.28Unix_Only.29
#
# List of CPackRPM specific variables:
#
# .. variable:: CPACK_RPM_PACKAGE_COMPONENT
#
#  Enable component packaging for CPackRPM
#
#  * Mandatory : NO
#  * Default   : OFF
#
#  If enabled (ON) multiple packages are generated. By default a single package
#  containing files of all components is generated.
54
#
55
# .. variable:: CPACK_RPM_PACKAGE_SUMMARY
56
#               CPACK_RPM_<component>_PACKAGE_SUMMARY
57
#
58
#  The RPM package summary.
59
#
60
#  * Mandatory : YES
61
#  * Default   : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
62
#
63
64
65
66
67
68
69
70
# .. variable:: CPACK_RPM_DEBUGINFO_PACKAGE
#               CPACK_RPM_<component>_DEBUGINFO_PACKAGE
#
#  Option to additionally generate debuginfo RPM package(s).
#
#  * Mandatory : NO
#  * Default   : OFF
#
71
# .. variable:: CPACK_RPM_PACKAGE_NAME
72
#               CPACK_RPM_<component>_PACKAGE_NAME
73
#
74
#  The RPM package name.
75
#
76
#  * Mandatory : YES
77
#  * Default   : :variable:`CPACK_PACKAGE_NAME`
78
#
79
80
81
82
83
84
85
86
87
88
89
# .. variable:: CPACK_RPM_FILE_NAME
#               CPACK_RPM_<component>_FILE_NAME
#
#  Package file name.
#
#  * Mandatory : YES
#  * Default   : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
#                replaced by '-'
#
#  This may be set to ``RPM-DEFAULT`` to allow rpmbuild tool to generate package
#  file name by itself.
90
#  Alternatively provided package file name must end with ``.rpm`` suffix.
91
92
93
94
95
96
97
98
99
100
101
102
#
#  .. note::
#
#    By using user provided spec file, rpm macro extensions such as for
#    generating debuginfo packages or by simply using multiple components more
#    than one rpm file may be generated, either from a single spec file or from
#    multiple spec files (each component execution produces it's own spec file).
#    In such cases duplicate file names may occur as a result of this variable
#    setting or spec file content structure. Duplicate files get overwritten
#    and it is up to the packager to set the variables in a manner that will
#    prevent such errors.
#
103
# .. variable:: CPACK_RPM_PACKAGE_VERSION
104
#
105
#  The RPM package version.
106
#
107
#  * Mandatory : YES
108
#  * Default   : :variable:`CPACK_PACKAGE_VERSION`
109
#
110
# .. variable:: CPACK_RPM_PACKAGE_ARCHITECTURE
111
#               CPACK_RPM_<component>_PACKAGE_ARCHITECTURE
112
#
113
#  The RPM package architecture.
114
#
115
#  * Mandatory : YES
116
#  * Default   : Native architecture output by ``uname -m``
117
#
118
#  This may be set to ``noarch`` if you know you are building a noarch package.
119
#
120
# .. variable:: CPACK_RPM_PACKAGE_RELEASE
121
#
122
#  The RPM package release.
123
#
124
125
#  * Mandatory : YES
#  * Default   : 1
126
#
127
128
#  This is the numbering of the RPM package itself, i.e. the version of the
#  packaging and not the version of the content (see
129
130
#  :variable:`CPACK_RPM_PACKAGE_VERSION`). One may change the default value if
#  the previous packaging was buggy and/or you want to put here a fancy Linux
131
#  distro specific numbering.
132
#
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# .. note::
#
#  This is the string that goes into the RPM ``Release:`` field. Some distros
#  (e.g. Fedora, CentOS) require ``1%{?dist}`` format and not just a number.
#  ``%{?dist}`` part can be added by setting :variable:`CPACK_RPM_PACKAGE_RELEASE_DIST`.
#
# .. variable:: CPACK_RPM_PACKAGE_RELEASE_DIST
#
#  The dist tag that is added  RPM ``Release:`` field.
#
#  * Mandatory : NO
#  * Default   : OFF
#
#  This is the reported ``%{dist}`` tag from the current distribution or empty
#  ``%{dist}`` if RPM macro is not set. If this variable is set then RPM
#  ``Release:`` field value is set to ``${CPACK_RPM_PACKAGE_RELEASE}%{?dist}``.
#
150
# .. variable:: CPACK_RPM_PACKAGE_LICENSE
151
#
152
#  The RPM package license policy.
153
#
154
155
#  * Mandatory : YES
#  * Default   : "unknown"
156
#
157
# .. variable:: CPACK_RPM_PACKAGE_GROUP
158
#               CPACK_RPM_<component>_PACKAGE_GROUP
159
#
160
#  The RPM package group.
161
#
162
163
#  * Mandatory : YES
#  * Default   : "unknown"
164
#
165
# .. variable:: CPACK_RPM_PACKAGE_VENDOR
166
#
167
#  The RPM package vendor.
168
#
169
170
#  * Mandatory : YES
#  * Default   : CPACK_PACKAGE_VENDOR if set or "unknown"
171
#
172
# .. variable:: CPACK_RPM_PACKAGE_URL
173
#               CPACK_RPM_<component>_PACKAGE_URL
174
#
175
#  The projects URL.
176
#
177
178
#  * Mandatory : NO
#  * Default   : -
179
#
180
# .. variable:: CPACK_RPM_PACKAGE_DESCRIPTION
181
#               CPACK_RPM_<component>_PACKAGE_DESCRIPTION
182
#
183
#  RPM package description.
184
#
185
#  * Mandatory : YES
186
187
188
#  * Default : :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION` (component
#    based installers only) if set, :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`
#    if set or "no package description available"
189
#
190
# .. variable:: CPACK_RPM_COMPRESSION_TYPE
191
#
192
#  RPM compression type.
193
#
194
195
#  * Mandatory : NO
#  * Default   : -
196
#
197
198
#  May be used to override RPM compression type to be used to build the
#  RPM. For example some Linux distribution now default to lzma or xz
199
200
201
202
203
204
205
206
207
#  compression whereas older cannot use such RPM. Using this one can enforce
#  compression type to be used.
#
#  Possible values are:
#
#  - lzma
#  - xz
#  - bzip2
#  - gzip
208
#
209
210
211
212
213
214
215
216
217
218
219
220
221
# .. variable:: CPACK_RPM_PACKAGE_AUTOREQ
#               CPACK_RPM_<component>_PACKAGE_AUTOREQ
#
#  RPM spec autoreq field.
#
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to enable (1, yes) or disable (0, no) automatic shared libraries
#  dependency detection. Dependencies are added to requires list.
#
#  .. note::
#
222
#    By default automatic dependency detection is enabled by rpm generator.
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#
# .. variable:: CPACK_RPM_PACKAGE_AUTOPROV
#               CPACK_RPM_<component>_PACKAGE_AUTOPROV
#
#  RPM spec autoprov field.
#
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to enable (1, yes) or disable (0, no) automatic listing of shared
#  libraries that are provided by the package. Shared libraries are added to
#  provides list.
#
#  .. note::
#
238
#    By default automatic provides detection is enabled by rpm generator.
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#
# .. variable:: CPACK_RPM_PACKAGE_AUTOREQPROV
#               CPACK_RPM_<component>_PACKAGE_AUTOREQPROV
#
#  RPM spec autoreqprov field.
#
#  * Mandatory : NO
#  * Default   : -
#
#  Variable enables/disables autoreq and autoprov at the same time.
#  See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and :variable:`CPACK_RPM_PACKAGE_AUTOPROV`
#  for more details.
#
#  .. note::
#
254
#    By default automatic detection feature is enabled by rpm.
255
#
256
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES
257
#               CPACK_RPM_<component>_PACKAGE_REQUIRES
258
#
259
#  RPM spec requires field.
260
#
261
262
#  * Mandatory : NO
#  * Default   : -
263
#
264
#  May be used to set RPM dependencies (requires). Note that you must enclose
265
#  the complete requires string between quotes, for example::
266
#
267
#   set(CPACK_RPM_PACKAGE_REQUIRES "python >= 2.5.0, cmake >= 2.8")
268
#
269
#  The required package list of an RPM file could be printed with::
270
#
271
#   rpm -qp --requires file.rpm
272
#
273
274
275
276
277
278
279
280
# .. variable:: CPACK_RPM_PACKAGE_CONFLICTS
#               CPACK_RPM_<component>_PACKAGE_CONFLICTS
#
#  RPM spec conflicts field.
#
#  * Mandatory : NO
#  * Default   : -
#
281
282
#  May be used to set negative RPM dependencies (conflicts). Note that you must
#  enclose the complete requires string between quotes, for example::
283
284
285
286
287
288
289
#
#   set(CPACK_RPM_PACKAGE_CONFLICTS "libxml2")
#
#  The conflicting package list of an RPM file could be printed with::
#
#   rpm -qp --conflicts file.rpm
#
290
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PRE
291
#               CPACK_RPM_<component>_PACKAGE_REQUIRES_PRE
292
293
294
295
296
297
#
#  RPM spec requires(pre) field.
#
#  * Mandatory : NO
#  * Default   : -
#
298
299
#  May be used to set RPM preinstall dependencies (requires(pre)). Note that
#  you must enclose the complete requires string between quotes, for example::
300
301
302
303
#
#   set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils, initscripts")
#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POST
304
#               CPACK_RPM_<component>_PACKAGE_REQUIRES_POST
305
306
307
308
309
310
#
#  RPM spec requires(post) field.
#
#  * Mandatory : NO
#  * Default   : -
#
311
312
#  May be used to set RPM postinstall dependencies (requires(post)). Note that
#  you must enclose the complete requires string between quotes, for example::
313
314
315
#
#   set(CPACK_RPM_PACKAGE_REQUIRES_POST "shadow-utils, initscripts")
#
316
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POSTUN
317
#               CPACK_RPM_<component>_PACKAGE_REQUIRES_POSTUN
318
319
320
321
322
323
#
#  RPM spec requires(postun) field.
#
#  * Mandatory : NO
#  * Default   : -
#
324
325
326
#  May be used to set RPM postuninstall dependencies (requires(postun)). Note
#  that you must enclose the complete requires string between quotes, for
#  example::
327
328
329
330
#
#   set(CPACK_RPM_PACKAGE_REQUIRES_POSTUN "shadow-utils, initscripts")
#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PREUN
331
#               CPACK_RPM_<component>_PACKAGE_REQUIRES_PREUN
332
333
334
335
336
337
#
#  RPM spec requires(preun) field.
#
#  * Mandatory : NO
#  * Default   : -
#
338
339
#  May be used to set RPM preuninstall dependencies (requires(preun)). Note that
#  you must enclose the complete requires string between quotes, for example::
340
341
342
#
#   set(CPACK_RPM_PACKAGE_REQUIRES_PREUN "shadow-utils, initscripts")
#
343
# .. variable:: CPACK_RPM_PACKAGE_SUGGESTS
344
#               CPACK_RPM_<component>_PACKAGE_SUGGESTS
345
#
346
#  RPM spec suggest field.
347
#
348
349
#  * Mandatory : NO
#  * Default   : -
350
#
351
#  May be used to set weak RPM dependencies (suggests). Note that you must
352
#  enclose the complete requires string between quotes.
353
#
354
# .. variable:: CPACK_RPM_PACKAGE_PROVIDES
355
#               CPACK_RPM_<component>_PACKAGE_PROVIDES
356
#
357
#  RPM spec provides field.
358
#
359
360
#  * Mandatory : NO
#  * Default   : -
361
#
362
#  May be used to set RPM dependencies (provides). The provided package list
363
#  of an RPM file could be printed with::
364
#
365
#   rpm -qp --provides file.rpm
366
#
367
# .. variable:: CPACK_RPM_PACKAGE_OBSOLETES
368
#               CPACK_RPM_<component>_PACKAGE_OBSOLETES
369
#
370
#  RPM spec obsoletes field.
371
#
372
373
#  * Mandatory : NO
#  * Default   : -
374
#
375
#  May be used to set RPM packages that are obsoleted by this one.
376
#
377
# .. variable:: CPACK_RPM_PACKAGE_RELOCATABLE
378
#
379
#  build a relocatable RPM.
380
#
381
382
#  * Mandatory : NO
#  * Default   : CPACK_PACKAGE_RELOCATABLE
383
#
384
385
386
#  If this variable is set to TRUE or ON CPackRPM will try
#  to build a relocatable RPM package. A relocatable RPM may
#  be installed using::
387
#
388
#   rpm --prefix or --relocate
389
#
390
391
392
393
#  in order to install it at an alternate place see rpm(8). Note that
#  currently this may fail if :variable:`CPACK_SET_DESTDIR` is set to ``ON``. If
#  :variable:`CPACK_SET_DESTDIR` is set then you will get a warning message but
#  if there is file installed with absolute path you'll get unexpected behavior.
394
#
395
# .. variable:: CPACK_RPM_SPEC_INSTALL_POST
396
#
397
398
#  Deprecated - use :variable:`CPACK_RPM_POST_INSTALL_SCRIPT_FILE` instead.
#
399
400
401
#  * Mandatory : NO
#  * Default   : -
#  * Deprecated: YES
402
#
403
#  This way of specifying post-install script is deprecated, use
404
#  :variable:`CPACK_RPM_POST_INSTALL_SCRIPT_FILE`.
405
#  May be used to set an RPM post-install command inside the spec file.
406
#  For example setting it to ``/bin/true`` may be used to prevent
407
#  rpmbuild to strip binaries.
408
#
409
# .. variable:: CPACK_RPM_SPEC_MORE_DEFINE
410
#
411
#  RPM extended spec definitions lines.
412
#
413
414
#  * Mandatory : NO
#  * Default   : -
415
#
416
#  May be used to add any ``%define`` lines to the generated spec file.
417
#
418
# .. variable:: CPACK_RPM_PACKAGE_DEBUG
419
#
420
#  Toggle CPackRPM debug output.
421
#
422
423
#  * Mandatory : NO
#  * Default   : -
424
#
425
426
#  May be set when invoking cpack in order to trace debug information
#  during CPack RPM run. For example you may launch CPack like this::
427
#
428
#   cpack -D CPACK_RPM_PACKAGE_DEBUG=1 -G RPM
429
#
430
# .. variable:: CPACK_RPM_USER_BINARY_SPECFILE
431
#               CPACK_RPM_<componentName>_USER_BINARY_SPECFILE
432
#
433
#  A user provided spec file.
434
#
435
436
#  * Mandatory : NO
#  * Default   : -
437
#
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
#  May be set by the user in order to specify a USER binary spec file
#  to be used by CPackRPM instead of generating the file.
#  The specified file will be processed by configure_file( @ONLY).
#
# .. variable:: CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE
#
#  Spec file template.
#
#  * Mandatory : NO
#  * Default   : -
#
#  If set CPack will generate a template for USER specified binary
#  spec file and stop with an error. For example launch CPack like this::
#
#   cpack -D CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE=1 -G RPM
#
#  The user may then use this file in order to hand-craft is own
455
456
#  binary spec file which may be used with
#  :variable:`CPACK_RPM_USER_BINARY_SPECFILE`.
457
458
459
460
#
# .. variable:: CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
#               CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
#
461
462
#  Path to file containing pre (un)install script.
#
463
464
465
466
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to embed a pre (un)installation script in the spec file.
467
468
469
470
471
472
#  The referred script file (or both) will be read and directly
#  put after the ``%pre`` or ``%preun`` section
#  If :variable:`CPACK_RPM_PACKAGE_COMPONENT` is set to ON the (un)install
#  script for each component can be overridden with
#  ``CPACK_RPM_<COMPONENT>_PRE_INSTALL_SCRIPT_FILE`` and
#  ``CPACK_RPM_<COMPONENT>_PRE_UNINSTALL_SCRIPT_FILE``.
473
474
475
476
477
478
479
#  One may verify which scriptlet has been included with::
#
#   rpm -qp --scripts  package.rpm
#
# .. variable:: CPACK_RPM_POST_INSTALL_SCRIPT_FILE
#               CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
#
480
481
#  Path to file containing post (un)install script.
#
482
483
484
485
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to embed a post (un)installation script in the spec file.
486
487
488
489
490
491
#  The referred script file (or both) will be read and directly
#  put after the ``%post`` or ``%postun`` section.
#  If :variable:`CPACK_RPM_PACKAGE_COMPONENT` is set to ON the (un)install
#  script for each component can be overridden with
#  ``CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE`` and
#  ``CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE``.
492
493
494
495
496
497
498
499
500
501
#  One may verify which scriptlet has been included with::
#
#   rpm -qp --scripts  package.rpm
#
# .. variable:: CPACK_RPM_USER_FILELIST
#               CPACK_RPM_<COMPONENT>_USER_FILELIST
#
#  * Mandatory : NO
#  * Default   : -
#
502
503
504
#  May be used to explicitly specify ``%(<directive>)`` file line
#  in the spec file. Like ``%config(noreplace)`` or any other directive
#  that be found in the ``%files`` section. Since CPackRPM is generating
505
#  the list of files (and directories) the user specified files of
506
#  the ``CPACK_RPM_<COMPONENT>_USER_FILELIST`` list will be removed from
507
508
509
510
511
512
513
514
515
516
#  the generated list.
#
# .. variable:: CPACK_RPM_CHANGELOG_FILE
#
#  RPM changelog file.
#
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to embed a changelog in the spec file.
517
#  The referred file will be read and directly put after the ``%changelog``
518
519
520
521
522
523
524
525
526
527
528
529
530
#  section.
#
# .. variable:: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST
#
#  list of path to be excluded.
#
#  * Mandatory : NO
#  * Default   : /etc /etc/init.d /usr /usr/share /usr/share/doc /usr/bin /usr/lib /usr/lib64 /usr/include
#
#  May be used to exclude path (directories or files) from the auto-generated
#  list of paths discovered by CPack RPM. The defaut value contains a
#  reasonable set of values if the variable is not defined by the user. If the
#  variable is defined by the user then CPackRPM will NOT any of the default
531
532
#  path. If you want to add some path to the default list then you can use
#  :variable:`CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION` variable.
533
534
535
536
#
# .. variable:: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
#
#  additional list of path to be excluded.
537
#
538
539
#  * Mandatory : NO
#  * Default   : -
540
#
541
#  May be used to add more exclude path (directories or files) from the initial
542
543
#  default list of excluded paths. See
#  :variable:`CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST`.
544
545
546
#
# .. variable:: CPACK_RPM_RELOCATION_PATHS
#
547
548
#  Packages relocation paths list.
#
549
550
551
552
553
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to specify more than one relocation path per relocatable RPM.
#  Variable contains a list of relocation paths that if relative are prefixed
554
555
556
#  by the value of :variable:`CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX` or by the
#  value of :variable:`CPACK_PACKAGING_INSTALL_PREFIX` if the component version
#  is not provided.
557
558
559
560
#  Variable is not component based as its content can be used to set a different
#  path prefix for e.g. binary dir and documentation dir at the same time.
#  Only prefixes that are required by a certain component are added to that
#  component - component must contain at least one file/directory/symbolic link
561
562
563
#  with :variable:`CPACK_RPM_RELOCATION_PATHS` prefix for a certain relocation
#  path to be added. Package will not contain any relocation paths if there are
#  no files/directories/symbolic links on any of the provided prefix locations.
564
565
#  Packages that either do not contain any relocation paths or contain
#  files/directories/symbolic links that are outside relocation paths print
566
#  out an ``AUTHOR_WARNING`` that RPM will be partially relocatable.
567
568
569
#
# .. variable:: CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
#
570
571
#  Per component relocation path install prefix.
#
572
573
574
#  * Mandatory : NO
#  * Default   : CPACK_PACKAGING_INSTALL_PREFIX
#
575
576
#  May be used to set per component :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
#  for relocatable RPM packages.
577
578
579
580
#
# .. variable:: CPACK_RPM_NO_INSTALL_PREFIX_RELOCATION
#               CPACK_RPM_NO_<COMPONENT>_INSTALL_PREFIX_RELOCATION
#
581
582
#  Removal of default install prefix from relocation paths list.
#
583
584
585
586
587
588
#  * Mandatory : NO
#  * Default   : CPACK_PACKAGING_INSTALL_PREFIX or CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
#                are treated as one of relocation paths
#
#  May be used to remove CPACK_PACKAGING_INSTALL_PREFIX and CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
#  from relocatable RPM prefix paths.
589
#
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# .. variable:: CPACK_RPM_ADDITIONAL_MAN_DIRS
#
#  * Mandatory : NO
#  * Default   : -
#
#  May be used to set additional man dirs that could potentially be compressed
#  by brp-compress RPM macro. Variable content must be a list of regular
#  expressions that point to directories containing man files or to man files
#  directly. Note that in order to compress man pages a path must also be
#  present in brp-compress RPM script and that brp-compress script must be
#  added to RPM configuration by the operating system.
#
#  Regular expressions that are added by default were taken from brp-compress
#  RPM macro:
#
#  - /usr/man/man.*
#  - /usr/man/.*/man.*
#  - /usr/info.*
#  - /usr/share/man/man.*
#  - /usr/share/man/.*/man.*
#  - /usr/share/info.*
#  - /usr/kerberos/man.*
#  - /usr/X11R6/man/man.*
#  - /usr/lib/perl5/man/man.*
#  - /usr/share/doc/.*/man/man.*
#  - /usr/lib/.*/man/man.*
#
Domen Vrankar's avatar
Domen Vrankar committed
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# .. variable:: CPACK_RPM_DEFAULT_USER
#               CPACK_RPM_<compName>_DEFAULT_USER
#
#  default user ownership of RPM content
#
#  * Mandatory : NO
#  * Default   : root
#
#  Value should be user name and not UID.
#  Note that <compName> must be in upper-case.
#
# .. variable:: CPACK_RPM_DEFAULT_GROUP
#               CPACK_RPM_<compName>_DEFAULT_GROUP
#
#  default group ownership of RPM content
#
#  * Mandatory : NO
#  * Default   : root
#
#  Value should be group name and not GID.
#  Note that <compName> must be in upper-case.
#
# .. variable:: CPACK_RPM_DEFAULT_FILE_PERMISSIONS
#               CPACK_RPM_<compName>_DEFAULT_FILE_PERMISSIONS
#
#  default permissions used for packaged files
#
#  * Mandatory : NO
#  * Default   : - (system default)
#
647
648
649
650
651
652
653
654
655
656
657
658
659
#  Accepted values are lists with ``PERMISSIONS``. Valid permissions
#  are:
#
#  - OWNER_READ
#  - OWNER_WRITE
#  - OWNER_EXECUTE
#  - GROUP_READ
#  - GROUP_WRITE
#  - GROUP_EXECUTE
#  - WORLD_READ
#  - WORLD_WRITE
#  - WORLD_EXECUTE
#
Domen Vrankar's avatar
Domen Vrankar committed
660
661
662
663
664
665
666
667
668
669
670
#  Note that <compName> must be in upper-case.
#
# .. variable:: CPACK_RPM_DEFAULT_DIR_PERMISSIONS
#               CPACK_RPM_<compName>_DEFAULT_DIR_PERMISSIONS
#
#  default permissions used for packaged directories
#
#  * Mandatory : NO
#  * Default   : - (system default)
#
#  Accepted values are lists with PERMISSIONS. Valid permissions
671
#  are the same as for :variable:`CPACK_RPM_DEFAULT_FILE_PERMISSIONS`.
Domen Vrankar's avatar
Domen Vrankar committed
672
673
#  Note that <compName> must be in upper-case.
#
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
# Packaging of Symbolic Links
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# CPackRPM supports packaging of symbolic links::
#
#   execute_process(COMMAND ${CMAKE_COMMAND}
#     -E create_symlink <relative_path_location> <symlink_name>)
#   install(FILES ${CMAKE_CURRENT_BINARY_DIR}/<symlink_name>
#     DESTINATION <symlink_location> COMPONENT libraries)
#
# Symbolic links will be optimized (paths will be shortened if possible)
# before being added to the package or if multiple relocation paths are
# detected, a post install symlink relocation script will be generated.
#
# Symbolic links may point to locations that are not packaged by the same
# package (either a different component or even not packaged at all) but
# those locations will be treated as if they were a part of the package
# while determining if symlink should be either created or present in a
# post install script - depending on relocation paths.
#
694
695
# Symbolic links that point to locations outside packaging path produce a
# warning and are treated as non relocatable permanent symbolic links.
696
#
697
# Currently there are a few limitations though:
698
699
700
701
702
703
704
705
706
707
708
#
# * For component based packaging component interdependency is not checked
#   when processing symbolic links. Symbolic links pointing to content of
#   a different component are treated the same way as if pointing to location
#   that will not be packaged.
#
# * Symbolic links pointing to a location through one or more intermediate
#   symbolic links will not be handled differently - if the intermediate
#   symbolic link(s) is also on a relocatable path, relocating it during
#   package installation may cause initial symbolic link to point to an
#   invalid location.
709

710
#=============================================================================
711
# Copyright 2007-2016 Kitware, Inc.
712
713
714
715
716
717
718
719
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
720
# (To distribute this file outside of CMake, substitute the full
721
722
#  License text for the above reference.)

723
# Author: Eric Noulard with the help of Alexander Neundorf.
Alexander Neundorf's avatar
   
Alexander Neundorf committed
724

Domen Vrankar's avatar
Domen Vrankar committed
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
function(get_unix_permissions_octal_notation PERMISSIONS_VAR RETURN_VAR)
  set(PERMISSIONS ${${PERMISSIONS_VAR}})
  list(LENGTH PERMISSIONS PERM_LEN_PRE)
  list(REMOVE_DUPLICATES PERMISSIONS)
  list(LENGTH PERMISSIONS PERM_LEN_POST)

  if(NOT ${PERM_LEN_PRE} EQUAL ${PERM_LEN_POST})
    message(FATAL_ERROR "${PERMISSIONS_VAR} contains duplicate values.")
  endif()

  foreach(PERMISSION_TYPE "OWNER" "GROUP" "WORLD")
    set(${PERMISSION_TYPE}_PERMISSIONS 0)

    foreach(PERMISSION ${PERMISSIONS})
      if("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_READ")
        math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 4")
      elseif("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_WRITE")
        math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 2")
      elseif("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_EXECUTE")
        math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 1")
      elseif(PERMISSION MATCHES "${PERMISSION_TYPE}.*")
        message(FATAL_ERROR "${PERMISSIONS_VAR} contains invalid values.")
      endif()
    endforeach()
  endforeach()

  set(${RETURN_VAR} "${OWNER_PERMISSIONS}${GROUP_PERMISSIONS}${WORLD_PERMISSIONS}" PARENT_SCOPE)
endfunction()

754
755
756
757
function(cpack_rpm_prepare_relocation_paths)
  # set appropriate prefix, remove possible trailing slash and convert backslashes to slashes
  if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX)
    file(TO_CMAKE_PATH "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX}" PATH_PREFIX)
758
759
  elseif(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_PREFIX)
    file(TO_CMAKE_PATH "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_PREFIX}" PATH_PREFIX)
760
761
762
763
764
765
766
767
768
  else()
    file(TO_CMAKE_PATH "${CPACK_PACKAGING_INSTALL_PREFIX}" PATH_PREFIX)
  endif()

  set(RPM_RELOCATION_PATHS "${CPACK_RPM_RELOCATION_PATHS}")
  list(REMOVE_DUPLICATES RPM_RELOCATION_PATHS)

  # set base path prefix
  if(EXISTS "${WDIR}/${PATH_PREFIX}")
769
    if(NOT CPACK_RPM_NO_INSTALL_PREFIX_RELOCATION AND
770
771
       NOT CPACK_RPM_NO_${CPACK_RPM_PACKAGE_COMPONENT}_INSTALL_PREFIX_RELOCATION AND
       NOT CPACK_RPM_NO_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_INSTALL_PREFIX_RELOCATION)
Daniel Pfeifer's avatar
Daniel Pfeifer committed
772
      string(APPEND TMP_RPM_PREFIXES "Prefix: ${PATH_PREFIX}\n")
773
774
775
776
777
778
      list(APPEND RPM_USED_PACKAGE_PREFIXES "${PATH_PREFIX}")

      if(CPACK_RPM_PACKAGE_DEBUG)
        message("CPackRPM:Debug: removing '${PATH_PREFIX}' from relocation paths")
      endif()
    endif()
779
780
781
782
  endif()

  # set other path prefixes
  foreach(RELOCATION_PATH ${RPM_RELOCATION_PATHS})
783
    if(IS_ABSOLUTE "${RELOCATION_PATH}")
784
785
786
787
788
789
      set(PREPARED_RELOCATION_PATH "${RELOCATION_PATH}")
    else()
      set(PREPARED_RELOCATION_PATH "${PATH_PREFIX}/${RELOCATION_PATH}")
    endif()

    if(EXISTS "${WDIR}/${PREPARED_RELOCATION_PATH}")
Daniel Pfeifer's avatar
Daniel Pfeifer committed
790
      string(APPEND TMP_RPM_PREFIXES "Prefix: ${PREPARED_RELOCATION_PATH}\n")
791
792
793
794
795
      list(APPEND RPM_USED_PACKAGE_PREFIXES "${PREPARED_RELOCATION_PATH}")
    endif()
  endforeach()

  # warn about all the paths that are not relocatable
796
797
798
799
800
801
  cmake_policy(PUSH)
    # Tell file(GLOB_RECURSE) not to follow directory symlinks
    # even if the project does not set this policy to NEW.
    cmake_policy(SET CMP0009 NEW)
    file(GLOB_RECURSE FILE_PATHS_ "${WDIR}/*")
  cmake_policy(POP)
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
  foreach(TMP_PATH ${FILE_PATHS_})
    string(LENGTH "${WDIR}" WDIR_LEN)
    string(SUBSTRING "${TMP_PATH}" ${WDIR_LEN} -1 TMP_PATH)
    unset(TMP_PATH_FOUND_)

    foreach(RELOCATION_PATH ${RPM_USED_PACKAGE_PREFIXES})
      file(RELATIVE_PATH REL_PATH_ "${RELOCATION_PATH}" "${TMP_PATH}")
      string(SUBSTRING "${REL_PATH_}" 0 2 PREFIX_)

      if(NOT "${PREFIX_}" STREQUAL "..")
        set(TPM_PATH_FOUND_ TRUE)
        break()
      endif()
    endforeach()

    if(NOT TPM_PATH_FOUND_)
      message(AUTHOR_WARNING "CPackRPM:Warning: Path ${TMP_PATH} is not on one of the relocatable paths! Package will be partially relocatable.")
    endif()
  endforeach()

822
  set(RPM_USED_PACKAGE_PREFIXES "${RPM_USED_PACKAGE_PREFIXES}" PARENT_SCOPE)
823
824
825
  set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}" PARENT_SCOPE)
endfunction()

826
function(cpack_rpm_prepare_content_list)
827
828
829
830
831
832
833
834
  # get files list
  cmake_policy(PUSH)
    cmake_policy(SET CMP0009 NEW)
    file(GLOB_RECURSE CPACK_RPM_INSTALL_FILES LIST_DIRECTORIES true RELATIVE "${WDIR}" "${WDIR}/*")
  cmake_policy(POP)
  set(CPACK_RPM_INSTALL_FILES "/${CPACK_RPM_INSTALL_FILES}")
  string(REPLACE ";" ";/" CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}")

835
836
837
838
839
840
841
842
  # if we are creating a relocatable package, omit parent directories of
  # CPACK_RPM_PACKAGE_PREFIX. This is achieved by building a "filter list"
  # which is passed to the find command that generates the content-list
  if(CPACK_RPM_PACKAGE_RELOCATABLE)
    # get a list of the elements in CPACK_RPM_PACKAGE_PREFIXES that are
    # destinct parent paths of other relocation paths and remove the
    # final element (so the install-prefix dir itself is not omitted
    # from the RPM's content-list)
843
    list(SORT RPM_USED_PACKAGE_PREFIXES)
844
    set(_DISTINCT_PATH "NOT_SET")
845
    foreach(_RPM_RELOCATION_PREFIX ${RPM_USED_PACKAGE_PREFIXES})
846
847
848
      if(NOT "${_RPM_RELOCATION_PREFIX}" MATCHES "${_DISTINCT_PATH}/.*")
        set(_DISTINCT_PATH "${_RPM_RELOCATION_PREFIX}")

849
        string(REPLACE "/" ";" _CPACK_RPM_PACKAGE_PREFIX_ELEMS " ${_RPM_RELOCATION_PREFIX}")
850
851
852
853
        cmake_policy(PUSH)
          cmake_policy(SET CMP0007 NEW)
          list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1)
        cmake_policy(POP)
854
855
856
857
858
        unset(_TMP_LIST)
        # Now generate all of the parent dirs of the relocation path
        foreach(_PREFIX_PATH_ELEM ${_CPACK_RPM_PACKAGE_PREFIX_ELEMS})
          list(APPEND _TMP_LIST "${_PREFIX_PATH_ELEM}")
          string(REPLACE ";" "/" _OMIT_DIR "${_TMP_LIST}")
859
860
          separate_arguments(_OMIT_DIR)
          list(APPEND _RPM_DIRS_TO_OMIT ${_OMIT_DIR})
861
862
863
864
865
866
867
868
869
        endforeach()
      endif()
    endforeach()
  endif()

  if(CPACK_RPM_PACKAGE_DEBUG)
    message("CPackRPM:Debug: Initial list of path to OMIT in RPM: ${_RPM_DIRS_TO_OMIT}")
  endif()

870
  if(NOT DEFINED CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
871
    set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST /etc /etc/init.d /usr /usr/share /usr/share/doc /usr/bin /usr/lib /usr/lib64 /usr/include)
872
    if(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION)
873
874
875
      if(CPACK_RPM_PACKAGE_DEBUG)
        message("CPackRPM:Debug: Adding ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION} to builtin omit list.")
      endif()
876
877
878
879
880
      list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST "${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION}")
    endif()
  endif()

  if(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
881
    if(CPACK_RPM_PACKAGE_DEBUG)
882
883
      message("CPackRPM:Debug: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST= ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST}")
    endif()
884
    list(APPEND _RPM_DIRS_TO_OMIT ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST})
885
886
887
888
889
890
  endif()

  if(CPACK_RPM_PACKAGE_DEBUG)
    message("CPackRPM:Debug: Final list of path to OMIT in RPM: ${_RPM_DIRS_TO_OMIT}")
  endif()

891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
  list(REMOVE_ITEM CPACK_RPM_INSTALL_FILES ${_RPM_DIRS_TO_OMIT})

  # add man paths that will be compressed
  # (copied from /usr/lib/rpm/brp-compress - script that does the actual
  # compressing)
  list(APPEND MAN_LOCATIONS "/usr/man/man.*" "/usr/man/.*/man.*" "/usr/info.*"
    "/usr/share/man/man.*" "/usr/share/man/.*/man.*" "/usr/share/info.*"
    "/usr/kerberos/man.*" "/usr/X11R6/man/man.*" "/usr/lib/perl5/man/man.*"
    "/usr/share/doc/.*/man/man.*" "/usr/lib/.*/man/man.*")

  if(CPACK_RPM_ADDITIONAL_MAN_DIRS)
    if(CPACK_RPM_PACKAGE_DEBUG)
      message("CPackRPM:Debug: CPACK_RPM_ADDITIONAL_MAN_DIRS= ${CPACK_RPM_ADDITIONAL_MAN_DIRS}")
    endif()
    list(APPEND MAN_LOCATIONS ${CPACK_RPM_ADDITIONAL_MAN_DIRS})
  endif()

  foreach(PACK_LOCATION IN LISTS CPACK_RPM_INSTALL_FILES)
    foreach(MAN_LOCATION IN LISTS MAN_LOCATIONS)
      # man pages are files inside a certain location
      if(PACK_LOCATION MATCHES "${MAN_LOCATION}/"
        AND NOT IS_DIRECTORY "${WDIR}${PACK_LOCATION}"
        AND NOT IS_SYMLINK "${WDIR}${PACK_LOCATION}")
        list(FIND CPACK_RPM_INSTALL_FILES "${PACK_LOCATION}" INDEX)
        # insert file location that covers compressed man pages
        # even if using a wildcard causes duplicates as those are
        # handled by RPM and we still keep the same file list
        # in spec file - wildcard only represents file type (e.g. .gz)
        list(INSERT CPACK_RPM_INSTALL_FILES ${INDEX} "${PACK_LOCATION}*")
        # remove file location that doesn't cover compressed man pages
        math(EXPR INDEX ${INDEX}+1)
        list(REMOVE_AT CPACK_RPM_INSTALL_FILES ${INDEX})

        break()
      endif()
    endforeach()
  endforeach()
928
929
930
931

  set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}" PARENT_SCOPE)
endfunction()

932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
function(cpack_rpm_symlink_get_relocation_prefixes LOCATION PACKAGE_PREFIXES RETURN_VARIABLE)
  foreach(PKG_PREFIX IN LISTS PACKAGE_PREFIXES)
    string(REGEX MATCH "^${PKG_PREFIX}/.*" FOUND_ "${LOCATION}")
    if(FOUND_)
      list(APPEND TMP_PREFIXES "${PKG_PREFIX}")
    endif()
  endforeach()

  set(${RETURN_VARIABLE} "${TMP_PREFIXES}" PARENT_SCOPE)
endfunction()

function(cpack_rpm_symlink_create_relocation_script PACKAGE_PREFIXES)
  list(LENGTH PACKAGE_PREFIXES LAST_INDEX)
  set(SORTED_PACKAGE_PREFIXES "${PACKAGE_PREFIXES}")
  list(SORT SORTED_PACKAGE_PREFIXES)
  list(REVERSE SORTED_PACKAGE_PREFIXES)
  math(EXPR LAST_INDEX ${LAST_INDEX}-1)

  foreach(SYMLINK_INDEX RANGE ${LAST_INDEX})
    list(GET SORTED_PACKAGE_PREFIXES ${SYMLINK_INDEX} SRC_PATH)
    list(FIND PACKAGE_PREFIXES "${SRC_PATH}" SYMLINK_INDEX) # reverse magic
    string(LENGTH "${SRC_PATH}" SRC_PATH_LEN)

    set(PARTS_CNT 0)
    set(SCRIPT_PART "if [ \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}\" != \"${SRC_PATH}\" ]; then\n")

    # both paths relocated
    foreach(POINT_INDEX RANGE ${LAST_INDEX})
      list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
      list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
      string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)

      if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
        if("${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
          set(INDENT "")
        else()
Daniel Pfeifer's avatar
Daniel Pfeifer committed
968
          string(APPEND SCRIPT_PART "  if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
          set(INDENT "  ")
        endif()

        foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
          math(EXPR PARTS_CNT ${PARTS_CNT}+1)

          math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
          list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
          string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)

          math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
          string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)

          math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
          string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)

Daniel Pfeifer's avatar
Daniel Pfeifer committed
985
986
987
988
          string(APPEND SCRIPT_PART "  ${INDENT}if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
          string(APPEND SCRIPT_PART "    ${INDENT}ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
          string(APPEND SCRIPT_PART "    ${INDENT}CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
          string(APPEND SCRIPT_PART "  ${INDENT}fi\n")
989
990
991
        endforeach()

        if(NOT "${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
Daniel Pfeifer's avatar
Daniel Pfeifer committed
992
          string(APPEND SCRIPT_PART "  fi\n")
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
        endif()
      endif()
    endforeach()

    # source path relocated
    if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
      foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
        math(EXPR PARTS_CNT ${PARTS_CNT}+1)

        math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
        list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
        string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)

        math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
        string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)

        math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
        string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)

Daniel Pfeifer's avatar
Daniel Pfeifer committed
1012
1013
1014
1015
        string(APPEND SCRIPT_PART "  if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
        string(APPEND SCRIPT_PART "    ln -s \"${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
        string(APPEND SCRIPT_PART "    CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
        string(APPEND SCRIPT_PART "  fi\n")
1016
1017
1018
1019
1020
      endforeach()
    endif()

    if(PARTS_CNT)
      set(SCRIPT "${SCRIPT_PART}")
Daniel Pfeifer's avatar
Daniel Pfeifer committed
1021
      string(APPEND SCRIPT "fi\n")
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
    endif()
  endforeach()

  # point path relocated
  foreach(POINT_INDEX RANGE ${LAST_INDEX})
    list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
    list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
    string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)

    if(_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
Daniel Pfeifer's avatar
Daniel Pfeifer committed
1032
      string(APPEND SCRIPT "if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043

      foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
        math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
        list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
        string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)

        string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)

        math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
        string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)

Daniel Pfeifer's avatar
Daniel Pfeifer committed
1044
1045
1046
1047
        string(APPEND SCRIPT "  if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
        string(APPEND SCRIPT "    ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"${SYMLINK_}\"\n")
        string(APPEND SCRIPT "    CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
        string(APPEND SCRIPT "  fi\n")
1048
1049
      endforeach()

Daniel Pfeifer's avatar
Daniel Pfeifer committed
1050
      string(APPEND SCRIPT "fi\n")
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
    endif()
  endforeach()

  # no path relocated
  if(_RPM_RELOCATION_SCRIPT_X_X)
    foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_X)
      math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
      list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
      string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)

      string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)

      math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
      string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)

Daniel Pfeifer's avatar
Daniel Pfeifer committed
1066
1067
1068
      string(APPEND SCRIPT "if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
      string(APPEND SCRIPT "  ln -s \"${POINT_}\" \"${SYMLINK_}\"\n")
      string(APPEND SCRIPT "fi\n")
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
    endforeach()
  endif()

  set(RPM_SYMLINK_POSTINSTALL "${SCRIPT}" PARENT_SCOPE)
endfunction()

function(cpack_rpm_symlink_add_for_relocation_script PACKAGE_PREFIXES SYMLINK SYMLINK_RELOCATION_PATHS POINT POINT_RELOCATION_PATHS)
  list(LENGTH SYMLINK_RELOCATION_PATHS SYMLINK_PATHS_COUTN)
  list(LENGTH POINT_RELOCATION_PATHS POINT_PATHS_COUNT)

  list(APPEND _RPM_RELOCATION_SCRIPT_PAIRS "${SYMLINK}:${POINT}")
  list(LENGTH _RPM_RELOCATION_SCRIPT_PAIRS PAIR_NO)

  if(SYMLINK_PATHS_COUTN)
    foreach(SYMLINK_RELOC_PATH IN LISTS SYMLINK_RELOCATION_PATHS)
      list(FIND PACKAGE_PREFIXES "${SYMLINK_RELOC_PATH}" SYMLINK_INDEX)

      # source path relocated
      list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X "${PAIR_NO}")
      list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X")

      foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
        list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)

        # both paths relocated
        list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX} "${PAIR_NO}")
        list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX}")

        # point path relocated
        list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
        list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
      endforeach()
    endforeach()
  elseif(POINT_PATHS_COUNT)
    foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
      list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)

      # point path relocated
      list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
      list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
    endforeach()
  endif()

  # no path relocated
  list(APPEND _RPM_RELOCATION_SCRIPT_X_X "${PAIR_NO}")
  list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_X")

  # place variables into parent scope
  foreach(VAR IN LISTS RELOCATION_VARS)
    set(${VAR} "${${VAR}}" PARENT_SCOPE)
  endforeach()
  set(_RPM_RELOCATION_SCRIPT_PAIRS "${_RPM_RELOCATION_SCRIPT_PAIRS}" PARENT_SCOPE)
  set(REQUIRES_SYMLINK_RELOCATION_SCRIPT "true" PARENT_SCOPE)
  set(DIRECTIVE "%ghost " PARENT_SCOPE)
endfunction()

function(cpack_rpm_prepare_install_files INSTALL_FILES_LIST WDIR PACKAGE_PREFIXES IS_RELOCATABLE)
  # Prepend directories in ${CPACK_RPM_INSTALL_FILES} with %dir
  # This is necessary to avoid duplicate files since rpmbuild does
  # recursion on its own when encountering a pathname which is a directory
  # which is not flagged as %dir
  string(STRIP "${INSTALL_FILES_LIST}" INSTALL_FILES_LIST)
  string(REPLACE "\n" ";" INSTALL_FILES_LIST
                          "${INSTALL_FILES_LIST}")
  string(REPLACE "\"" "" INSTALL_FILES_LIST
                          "${INSTALL_FILES_LIST}")
  string(LENGTH "${WDIR}" WDR_LEN_)

  list(SORT INSTALL_FILES_LIST) # make file order consistent on all platforms

  foreach(F IN LISTS INSTALL_FILES_LIST)
    unset(DIRECTIVE)

    if(IS_SYMLINK "${WDIR}/${F}")
      if(IS_RELOCATABLE)
        # check that symlink has relocatable format
        get_filename_component(SYMLINK_LOCATION_ "${WDIR}/${F}" DIRECTORY)
        execute_process(COMMAND ls -la "${WDIR}/${F}"
                  WORKING_DIRECTORY "${WDIR}"
                  OUTPUT_VARIABLE SYMLINK_POINT_
                  OUTPUT_STRIP_TRAILING_WHITESPACE)

        string(FIND "${SYMLINK_POINT_}" "->" SYMLINK_POINT_INDEX_ REVERSE)
        math(EXPR SYMLINK_POINT_INDEX_ ${SYMLINK_POINT_INDEX_}+3)
        string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)

        # get destination path
        string(SUBSTRING "${SYMLINK_POINT_}" ${SYMLINK_POINT_INDEX_} ${SYMLINK_POINT_LENGTH_} SYMLINK_POINT_)

        # check if path is relative or absolute
        string(SUBSTRING "${SYMLINK_POINT_}" 0 1 SYMLINK_IS_ABSOLUTE_)

        if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "/")
          # prevent absolute paths from having /../ or /./ section inside of them
          get_filename_component(SYMLINK_POINT_ "${SYMLINK_POINT_}" ABSOLUTE)
        else()
          # handle relative path
          get_filename_component(SYMLINK_POINT_ "${SYMLINK_LOCATION_}/${SYMLINK_POINT_}" ABSOLUTE)
        endif()

1169
1170
        # recalculate path length after conversion to canonical form
        string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
1171

1172
1173
1174
1175
1176
        if(SYMLINK_POINT_ MATCHES "${WDIR}/.*")
          # only symlinks that are pointing inside the packaging structure should be checked for relocation
          string(SUBSTRING "${SYMLINK_POINT_}" ${WDR_LEN_} -1 SYMLINK_POINT_WD_)
          cpack_rpm_symlink_get_relocation_prefixes("${F}" "${PACKAGE_PREFIXES}" "SYMLINK_RELOCATIONS")
          cpack_rpm_symlink_get_relocation_prefixes("${SYMLINK_POINT_WD_}" "${PACKAGE_PREFIXES}" "POINT_RELOCATIONS")
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
          list(LENGTH SYMLINK_RELOCATIONS SYMLINK_RELOCATIONS_COUNT)
          list(LENGTH POINT_RELOCATIONS POINT_RELOCATIONS_COUNT)
        else()
          # location pointed to is ouside WDR so it should be treated as a permanent symlink
          set(SYMLINK_POINT_WD_ "${SYMLINK_POINT_}")

          unset(SYMLINK_RELOCATIONS)
          unset(POINT_RELOCATIONS)
          unset(SYMLINK_RELOCATIONS_COUNT)
          unset(POINT_RELOCATIONS_COUNT)

          message(AUTHOR_WARNING "CPackRPM:Warning: Symbolic link '${F}' points to location that is outside packaging path! Link will possibly not be relocatable.")
        endif()
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230

        if(SYMLINK_RELOCATIONS_COUNT AND POINT_RELOCATIONS_COUNT)
          # find matching
          foreach(SYMLINK_RELOCATION_PREFIX IN LISTS SYMLINK_RELOCATIONS)
            list(FIND POINT_RELOCATIONS "${SYMLINK_RELOCATION_PREFIX}" FOUND_INDEX)
            if(NOT ${FOUND_INDEX} EQUAL -1)
              break()
            endif()
          endforeach()

          if(NOT ${FOUND_INDEX} EQUAL -1)
            # symlinks have the same subpath
            if(${SYMLINK_RELOCATIONS_COUNT} EQUAL 1 AND ${POINT_RELOCATIONS_COUNT} EQUAL 1)
              # permanent symlink
              get_filename_component(SYMLINK_LOCATION_ "${F}" DIRECTORY)
              file(RELATIVE_PATH FINAL_PATH_ ${SYMLINK_LOCATION_} ${SYMLINK_POINT_WD_})
              execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${FINAL_PATH_}" "${WDIR}/${F}")
            else()
              # relocation subpaths
              cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
                  "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
            endif()
          else()
            # not on the same relocation path
            cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
                "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
          endif()
        elseif(POINT_RELOCATIONS_COUNT)
          # point is relocatable
          cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
              "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
        else()
          # is not relocatable or points to non relocatable path - permanent symlink
          execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${SYMLINK_POINT_WD_}" "${WDIR}/${F}")
        endif()
      endif()
    elseif(IS_DIRECTORY "${WDIR}/${F}")
      set(DIRECTIVE "%dir ")
    endif()

Daniel Pfeifer's avatar
Daniel Pfeifer committed
1231
    string(APPEND INSTALL_FILES "${DIRECTIVE}\"${F}\"\n")
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  endforeach()

  if(REQUIRES_SYMLINK_RELOCATION_SCRIPT)
    cpack_rpm_symlink_create_relocation_script("${PACKAGE_PREFIXES}")
  endif()

  set(RPM_SYMLINK_POSTINSTALL "${RPM_SYMLINK_POSTINSTALL}" PARENT_SCOPE)
  set(CPACK_RPM_INSTALL_FILES "${INSTALL_FILES}" PARENT_SCOPE)
endfunction()

1242
1243
if(CMAKE_BINARY_DIR)
  message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.")
1244
endif()
Alexander Neundorf's avatar
   
Alexander Neundorf committed
1245

1246
1247
if(NOT UNIX)
  message(FATAL_ERROR "CPackRPM.cmake may only be used under UNIX.")
1248
endif()
Alexander Neundorf's avatar
   
Alexander Neundorf committed
1249

1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
# We need to check if the binaries were compiled with debug symbols
# because without them the package will be useless
function(cpack_rpm_debugsymbol_check INSTALL_FILES WORKING_DIR)
  # With objdump we should check the debug symbols
  find_program(OBJDUMP_EXECUTABLE objdump)
  if(NOT OBJDUMP_EXECUTABLE)
    message(WARNING "CPackRPM: objdump binary could not be found!")
  endif()

  foreach(F IN LISTS INSTALL_FILES)
    execute_process(COMMAND "${OBJDUMP_EXECUTABLE}" -h ${WORKING_DIR}/${F}
                    WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}"
                    RESULT_VARIABLE OBJDUMP_EXEC_RESULT
                    OUTPUT_VARIABLE OBJDUMP_OUT)
    # Check that if the given file was executable or not
    if(NOT OBJDUMP_EXEC_RESULT)
      string(FIND "${OBJDUMP_OUT}" "debug" FIND_RESULT)
      if(NOT FIND_RESULT GREATER -1)
        message(WARNING "CPackRPM: File: ${F} does not contain debug symbols. They will possibly be missing from debuginfo package!")
      endif()
    endif()
  endforeach()
endfunction()

1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
function(cpack_rpm_variable_fallback OUTPUT_VAR_NAME)
  set(FALLBACK_VAR_NAMES ${ARGN})

  foreach(variable_name IN LISTS FALLBACK_VAR_NAMES)
    if(${variable_name})
      set(${OUTPUT_VAR_NAME} "${${variable_name}}" PARENT_SCOPE)
      break()
    endif()
  endforeach()
endfunction()

1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
function(cpack_rpm_generate_package)
  # rpmbuild is the basic command for building RPM package
  # it may be a simple (symbolic) link to rpm command.
  find_program(RPMBUILD_EXECUTABLE rpmbuild)

  # Check version of the rpmbuild tool this would be easier to
  # track bugs with users and CPackRPM debug mode.
  # We may use RPM version in order to check for available version dependent features
  if(RPMBUILD_EXECUTABLE)
    execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --version
                    OUTPUT_VARIABLE _TMP_VERSION
1296
1297
                    ERROR_QUIET
                    OUTPUT_STRIP_TRAILING_WHITESPACE)
1298
1299
1300
1301
1302
1303
    string(REGEX REPLACE "^.* " ""
           RPMBUILD_EXECUTABLE_VERSION
           ${_TMP_VERSION})
    if(CPACK_RPM_PACKAGE_DEBUG)
      message("CPackRPM:Debug: rpmbuild version is <${RPMBUILD_EXECUTABLE_VERSION}>")
    endif()
1304
  endif()
1305

1306
1307
1308
  if(NOT RPMBUILD_EXECUTABLE)
    message(FATAL_ERROR "RPM package requires rpmbuild executable")
  endif()
Alexander Neundorf's avatar
   
Alexander Neundorf committed
1309

1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
  # Display lsb_release output if DEBUG mode enable
  # This will help to diagnose problem with CPackRPM
  # because we will know on which kind of Linux we are
  if(CPACK_RPM_PACKAGE_DEBUG)
    find_program(LSB_RELEASE_EXECUTABLE lsb_release)
    if(LSB_RELEASE_EXECUTABLE)
      execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -a
                      OUTPUT_VARIABLE _TMP_LSB_RELEASE_OUTPUT
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
      string(REGEX REPLACE "\n" ", "
             LSB_RELEASE_OUTPUT
             ${_TMP_LSB_RELEASE_OUTPUT})
    else ()
      set(LSB_RELEASE_OUTPUT "lsb_release not installed/found!")
    endif()
    message("CPackRPM:Debug: LSB_RELEASE  = ${LSB_RELEASE_OUTPUT}")
  endif()
1328

1329
1330
1331
1332
1333
1334
1335
  # We may use RPM version in the future in order
  # to shut down warning about space in buildtree
  # some recent RPM version should support space in different places.
  # not checked [yet].
  if(CPACK_TOPLEVEL_DIRECTORY MATCHES ".* .*")
    message(FATAL_ERROR "${RPMBUILD_EXECUTABLE} can't handle paths with spaces, use a build directory without spaces for building RPMs.")
  endif()
1336

1337
1338
1339
1340
1341
1342
1343
1344
  # If rpmbuild is found
  # we try to discover alien since we may be on non RPM distro like Debian.
  # In this case we may try to to use more advanced features
  # like generating RPM directly from DEB using alien.
  # FIXME feature not finished (yet)
  find_program(ALIEN_EXECUTABLE alien)
  if(ALIEN_EXECUTABLE)
    message(STATUS "alien found, we may be on a Debian based distro.")
1345
1346
  endif()

1347
1348
1349
  # Are we packaging components ?
  if(CPACK_RPM_PACKAGE_COMPONENT)
    string(TOUPPER ${CPACK_RPM_PACKAGE_COMPONENT} CPACK_RPM_PACKAGE_COMPONENT_UPPER)
1350
  endif()
1351