I want to share my experience in adapting
fakeroot for use on a Mac in conjunction with Xcode. Fakeroot runs programs in a special environment that emulates a super-user session. Root rights may be required when building the installer using PackageMaker.
Historically, UNIX-like systems, including Mac OS X, have developed a certain approach to the distribution of software. At the core of any
package , be it deb, rpm or macOS pkg, is an archive that is deployed directly to the target file system. For example, if the package litware.pkg is deployed to the / usr / local / bin folder, and the archive contains the executable file lit with the access mask 0755 and the owner / group root: wheel, then the program will appear / usr / local / bin / lit (mask access 0755, owner / group root: wheel, ie the same as in the archive).
The package is created using special utilities (on Mac OS X, this is the console
packagemaker ). The utility puts into the package the contents of the folder that is specified at startup. The contents of the folder are included in the package as is. In particular, to make the correct litware.pkg, you must set the lit file by the owner root: wheel. Unfortunately, the success of this operation requires super user rights.
')
In Linux, this problem is bypassed using fakeroot. In fact, the programs are launched on behalf of the current user, but due to the interception of a number of system calls, the appearance of working as root is created. For example, chown and stat are intercepted. Chown successfully changes the owner: group file, and instead of actually modifying these fields on the file system (which would require a real root), the faked daemon remembers the information. The captured stat silently modifies the file parameters received from the file system based on the stored information about previous chown calls.
Fakeroot-mini
Fakeroot supports MacOS X up to version 10.7 inclusive. Unfortunately, fakeroot is missing from both popular port managers for Mac OS X (
MacPorts ,
Fink ). For correct work installation is necessary. In addition, classic fakeroot is inconvenient in conjunction with Xcode, since it is not possible to combine all scripts that require fakeroot into one fakeroot session. Different fakeroot sessions are completely independent: changes made in one session are not visible in another.
Based on the fakeroot code, I made a modified version of
fakeroot-mini with the following key features:
- Does not require installation. The only dynamic library is distributed. This library can be put directly into the repository, which removes the need to install additional software for building the project.
- Stores information in extended file system attributes. This solution fixes the problem of independent fakeroot sessions.
The principle of operation remains unchanged - a dynamic library that intercepts system calls is introduced into the programs being launched. The introduction of the library into the process is the regular feature of the dynamic loader, which is activated using the DYLD_INSERT_LIBRARIES environment variable:
/usr/bin/env DYLD_INSERT_LIBRARIES=<-> command [args]
Demo Xcode project
Under the
link you can download a demo project for Xcode. The project builds a simple console application + installer.

Project Settings:
DEPLOYMENT_LOCATION=YES DEPLOYMENT_POSTPROCESSING=YES INSTALL_OWNER=root INSTALL_GROUP=wheel STRIP_INSTALLED_PRODUCT=NO CHOWN=$(SRCROOT)/chown LIBFAKER=$(SRCROOT)/libfakermini-1.0.0.dylib PACKAGE=$(BUILT_PRODUCTS_DIR)/litware.pkg
DEPLOYMENT_LOCATION=YES
forces Xcode to decompose files by installation paths. For example, for the program lit, the installation path is / usr / local / bin / lit. With the DEPLOYMENT_LOCATION setting turned on, Xcode will put lit on the path $ (DSTROOT) / usr / local / bin / lit. The value of $ (DSTROOT) is configured, by default it is /tmp/<project name>.dst. The following file tree will be built in the temporary folder:
/tmp/litware.dst/ └── usr ├── local │ └── bin │ └── lit └── share └── man └── man1 └── lit.1
DEPLOYMENT_POSTPROCESSING=YES
includes additional file processing in $ (DSTROOT). Among other things, the owner of the $ (INSTALL_OWNER) and group $ (INSTALL_GROUP) files are set.
STRIP_INSTALLED_PRODUCT=NO
disables the removal of debug information in the collected binaries. Due to an error in Xcode, sometimes when rebuilding a project, debugging information is copied after it has completed strip and deleted everything.
CHOWN=$(SRCROOT)/chown
tells Xcode to use the script in the project source folder instead of the standard utility / usr / sbin / chown. The script sets up the fakeroot environment and calls the standard chown.
The variables LIBFAKER and PACKAGE are defined for convenience, they do not affect the behavior of Xcode.
The installer is made using the following script:
/usr/bin/env "DYLD_INSERT_LIBRARIES=${LIBFAKER}" \ /usr/sbin/mtree -f "${SRCROOT}/mtree.spec" -p "${DSTROOT}" -U && \ rm -f "${PACKAGE}" && \ /usr/bin/env "DYLD_INSERT_LIBRARIES=${LIBFAKER}" \ /Developer/usr/bin/packagemaker --id org.example.litware \ --root "${DSTROOT}" --no-recommend --target 10.5 \ --out "${PACKAGE}"
First,
mtree is launched in the fakeroot environment to configure the access mask and the owner / group for folders in $ (DSTROOT). This is necessary because although Xcode configures the access mask and owner / group for $ (DSTROOT) / usr / local / bin / lit, intermediate folders (ex: $ (DSTROOT) / usr / local / bin) are not processed.
For some unknown reason, packagemaker does not overwrite existing files when generating an installer. Therefore, we explicitly delete the existing installer file, if present, before running packagemaker in a fakeroot environment.
Conclusion
The described technology allows you to create installers directly in XCode, with a minimum of settings and without installing additional software. A number of tasks in the manufacture of the installer requires superuser rights. Fakeroot allows you to successfully perform these tasks to an unprivileged user.
Information may be useful to developers of system utilities and daemons for MacOS. The installer for regular user applications can usually be built without fakeroot.
Links
- Demo project for Xcode
- Original fakeroot
- Fakeroot-mini
- Using xcconfig files in Xcode
- Interception of system calls in Mac OS X