Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • CMake CMake
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 4.2k
    • Issues 4.2k
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 16
    • Merge requests 16
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Releases
  • Packages and registries
    • Packages and registries
    • Container Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • External wiki
    • External wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • CMakeCMake
  • CMakeCMake
  • Issues
  • #18413
Closed
Open
Issue created Oct 02, 2018 by Peter Wu@LekensteynContributor

Reproducible Builds - avoid embedding build directory in RPATH

CMake by default sets the RPATH property on executables that link to shared libraries in the same project. This makes it possible to run executables (like tests) from the build directory without having to set LD_LIBRARY_PATH.

Unfortunately this default behavior hurts reproducible builds in the sense that the build directory also becomes part of the build environment and thus the linked binaries are different. Even if the rpath is stripped as part of the install target, the damage is already done since the .note.gnu.build-id section was computed over the original file that contained the rpath. (Related post about this issue: https://lists.reproducible-builds.org/pipermail/rb-general/2018-October/001174.html)

As workaround, packagers can set CMAKE_SKIP_RPATH=ON to disable rpaths completely, but of course that will break in some cases (which then require LD_LIBRARY_PATH to be set before running tests).

Possible solutions:

  • Relink the executables on installation instead of merely changing the embedded rpath.
  • Make rpath relative to objects in the build directory using $ORIGIN. I would be in favor of this, would you be willing to accept patches for this feature?

To reproduce this issue, see the files below and use these commands (note difference in path length as well):

mkdir build-first  && (cd build-first  && cmake -GNinja .. && DESTDIR=$PWD/fs ninja install)
mkdir build-second && (cd build-second && cmake -GNinja .. && DESTDIR=$PWD/fs ninja install)
mkdir norp-first  && (cd norp-first  && cmake -GNinja .. -DCMAKE_SKIP_RPATH=ON && DESTDIR=$PWD/fs ninja install)
mkdir norp-second && (cd norp-second && cmake -GNinja .. -DCMAKE_SKIP_RPATH=ON && DESTDIR=$PWD/fs ninja install)
find * -name main -exec sha256sum {} \;

As you can see, the files with RPATHs embedded are all different even after stripping:

c21d8f3cc410be95758e306eac22bf34e65c0731cbc6dc311395554d41b405ab  build-first/fs/usr/local/bin/main
2720b92ff8147297e5f46b5f9048696f2a10816573f337db5b85be63fb13da15  build-first/main
2c03da564482d42acb47994a4464877f8570a662c33d738d72cf3d8248c0e761  build-second/fs/usr/local/bin/main
eb19657ffcf59d2a1e94d3c15d62d8bd147953a666ecba68b5880b4018a4dc74  build-second/main
9d7784b23366b3374272981d52dce4065bc4edbaa07dda51d644d52f02861bf7  norp-first/fs/usr/local/bin/main
9d7784b23366b3374272981d52dce4065bc4edbaa07dda51d644d52f02861bf7  norp-first/main
9d7784b23366b3374272981d52dce4065bc4edbaa07dda51d644d52f02861bf7  norp-second/fs/usr/local/bin/main
9d7784b23366b3374272981d52dce4065bc4edbaa07dda51d644d52f02861bf7  norp-second/main
diff -u <(objdump -xags build-first/main) <(objdump -xags build-second/main)
--- /dev/fd/63	2018-10-02 16:16:40.129184290 +0200
+++ /dev/fd/62	2018-10-02 16:16:40.129184290 +0200
@@ -1,6 +1,6 @@
 
-build-first/main:     file format elf64-x86-64
-build-first/main
+build-second/main:     file format elf64-x86-64
+build-second/main
 architecture: i386:x86-64, flags 0x00000150:
 HAS_SYMS, DYNAMIC, D_PAGED
 start address 0x0000000000001040
@@ -32,7 +32,7 @@
 Dynamic Section:
   NEEDED               libutils.so
   NEEDED               libc.so.6
-  RPATH                /tmp/cm/rep/build-first:
+  RPATH                /tmp/cm/rep/build-second:
   INIT                 0x0000000000001000
   FINI                 0x00000000000011c8
   INIT_ARRAY           0x0000000000003dc0
@@ -42,7 +42,7 @@
   GNU_HASH             0x0000000000000308
   STRTAB               0x00000000000003f0
   SYMTAB               0x0000000000000330
-  STRSZ                0x00000000000000ab
+  STRSZ                0x00000000000000ac
   SYMENT               0x0000000000000018
   DEBUG                0x0000000000000000
   PLTGOT               0x0000000000004000
@@ -74,7 +74,7 @@
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
   4 .dynsym       000000c0  0000000000000330  0000000000000330  00000330  2**3
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
-  5 .dynstr       000000ab  00000000000003f0  00000000000003f0  000003f0  2**0
+  5 .dynstr       000000ac  00000000000003f0  00000000000003f0  000003f0  2**0
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
   6 .gnu.version  00000010  000000000000049c  000000000000049c  0000049c  2**1
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
@@ -192,8 +192,8 @@
  02d4 00000000 03000000 02000000 00000000  ................
 Contents of section .note.gnu.build-id:
  02e4 04000000 14000000 03000000 474e5500  ............GNU.
- 02f4 72e392e0 84573517 b9d1f3ff 717a1639  r....W5.....qz.9
- 0304 5c49fbe0                             \I..            
+ 02f4 56ccc14f be0fa1d5 88616df4 a750af47  V..O.....am..P.G
+ 0304 da39beda                             .9..            
 Contents of section .gnu.hash:
  0308 02000000 07000000 01000000 06000000  ................
  0318 80100000 00000000 07000000 00000000  ................
@@ -222,7 +222,7 @@
  0460 697a6500 5f5f6c69 62635f73 74617274  ize.__libc_start
  0470 5f6d6169 6e00474c 4942435f 322e322e  _main.GLIBC_2.2.
  0480 35002f74 6d702f63 6d2f7265 702f6275  5./tmp/cm/rep/bu
- 0490 696c642d 66697273 743a00             ild-first:.     
+ 0490 696c642d 7365636f 6e643a00           ild-second:.    
 Contents of section .gnu.version:
  049c 00000000 02000200 00000000 02000000  ................
 Contents of section .gnu.version_r:
@@ -321,7 +321,7 @@
  3e68 f5feff6f 00000000 08030000 00000000  ...o............
  3e78 05000000 00000000 f0030000 00000000  ................
  3e88 06000000 00000000 30030000 00000000  ........0.......
- 3e98 0a000000 00000000 ab000000 00000000  ................
+ 3e98 0a000000 00000000 ac000000 00000000  ................
  3ea8 0b000000 00000000 18000000 00000000  ................
  3eb8 15000000 00000000 00000000 00000000  ................
  3ec8 03000000 00000000 00400000 00000000  .........@......

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(TestC LANGUAGES C)

add_library(utils SHARED utils.c)
add_executable(main main.c)
target_link_libraries(main utils)

include(GNUInstallDirs)
install(TARGETS main  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS utils LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

main.c

#include <stdio.h>
extern const char msg[];
int main() {
    puts(msg);
}

utils.c

const char msg[] = "hello";

FWIW, a similar Meson configuration uses $ORIGIN by default for rpath:

meson.build

project('TestC', 'c')
lib_utils = shared_library('utils', 'utils.c')
executable('main', 'main.c', link_with : lib_utils)

Build with:

$ CFLAGS=-fdebug-prefix-map=$PWD/$i=. CC=gcc meson setup m1 && ninja -C m1
$ CFLAGS=-fdebug-prefix-map=$PWD/$i=. CC=gcc meson setup m-two && ninja -C m-two
...
[2/5] gcc -Imain@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -g -fdebug-prefix-map=/tmp/cm/rep/m-two=.  -MD -MQ 'main@exe/main.c.o' -MF 'main@exe/main.c.o.d' -o 'main@exe/main.c.o' -c ../main.c
...
[5/5] gcc  -o main 'main@exe/main.c.o' -Wl,--no-undefined -Wl,--as-needed -fdebug-prefix-map=/tmp/cm/rep/m-two=. -Wl,--start-group libutils.so -Wl,--end-group '-Wl,-rpath,$ORIGIN/' -Wl,-rpath-link,/tmp/cm/rep/m-two/

and observe that the main executables are equal.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking