I can use pkgbuild and productbuild to create decent installers for an app. However, I need to create one that installs a bare executable and launch daemon, and I've hit a wall.
The crux of the problem seems to be the RootRelativeBundlePath item in the component list for pkgbuild. Since there's no bundle being installed, no path will work there, but I can't omit RootRelativeBundlePath either. So I can't generate the component package.
What do I do?
Found an answer to my own question, using the following command to build the component package, skipping the component list plist entirely:
pkgbuild --root software_root --install-location "/" --scripts scripts/ --identifier 'com.blah.pkg.blah' --version '1.0.0' installer.pkg
Related
I have a binary file, foo. Built using vercel/pkg.
I would like to bundle this in an installer for mac; A .pkg installer file.
It should install the binary in /usr/local/bin/foo.
Attempt:
$ cd Desktop // <--- foo binary is here
$ pkgbuild --identifier com.foo.pkg --install-location ./usr/local/bin/ --root ./ foo.pkg
This creates a .pkg file: foo.pkg on my desktop. And when i run foo.pkg, it installs the foo binary in /usr/local/bin correctly, except that it also leaves foo.pkg in /usr/local/bin also.
How can make pkgbuild avoid leaving foo.pkg inside /usr/local/bin?
UPDATE:
Based on this thread, I think it will work if i set BundleIsRelocatable to false. But I am not able to figure out how that is done.
When you pass --root, it takes everything in that folder and bakes it into the package. You're running pkgbuild in the root that you're building - it seems very likely that you have a copy of foo.pkg on your desktop that was created by an earlier run of pkgbuild. When you run it again, the old foo.pkg is now built into the new package.
Instead, point --root at a directory only containing the files you wish to package.
Otherwise, use --analyze to generate a component list of your root directory. Customize the resulting .plist as necessary (specifying the files you want to include and associated options), then feed it back into pkgbuild with --component-plist.
You should read the man page if you haven't already.
I have a build target set up in my Xcode project to create a package from a number of other targets. I added a build phase script that simply runs productbuild, which can automatically detect just about everything needed for my install:
productbuild \
--root "$INSTALL_ROOT" \
--identifier "$PRODUCT_BUNDLE_IDENTIFIER" \
"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.pkg"
This package works great functionally, but when I open it, the Installer.app is missing a name for it:
The window title should say "Install {Useful App}" and the little label below that should say "Welcome to the {Useful App} Installer".
How do I give my installer package a name/title for the UI? Can I do it while still using the --root option, or do I need to synthesize and then forever manually maintain a distribution file?
Use title as described in the Distribution Definition XML Schema Reference.
I have multiple package files, which I created using pkgbuild
pkgbuild --root /path/folder1 --install-location /Folder1 ~/pkg1.pkg
pkgbuild --root /path/folder2 --install-location /Folder2 ~/pkg2.pkg
Now I want to combine pkg1.pkg and pkg2.pkg to one single meta package using command line utilities. Is there an easy way to do that?
Thanks
productbuild is the built-in tool for that. The man page is pretty helpful.
productbuild --package ~/pkg1.pkg --package ~/pkg2.pkg ~/both.pkg
If you need to do anything fancy like background images or conditional installation of component packages, you can also provide productbuild with a Distribution file. See Apple's Docs for more information there.
I built a Mac OS X bundle Frequon Invaders.app, and it runs fine. The executable was created with Go. Then I packaged it like this:
$ pkgbuild --component 'Frequon Invaders.app' --install-location /Applications FrequonInvaders.pkg
pkgbuild: Adding component at /Users/Dad/Documents/projects/Frequon-Invaders-2.2/installer-macos/Frequon Invaders.app
pkgbuild: Wrote package to FrequonInvaders.pkg
When I open FrequonInvaders.pkg in Finder, I get a "install Frequon Invaders" window that lets me go through the motions of installing it, and the Summary part says "Installation was successful". But when I look in /Applications, it's not there. Indeed none of the files in the bundle were installed.
[Updated] After looking around, I found that the package appears to have been installed right on top of the original place that Frequon Invaders.app was originally built. It seems that the --install-location /Applications was completely ignored!
Question:
How do I use pkgbuild to build a package that is really installed where install-location said to install it?
How to debug Mac OS X pkg?
Debugging .pkg files is tricky because there's no easy way to get verbose output.
sudo installer -pkg my_package.pkg -target / -verbose
This may help understand the step that's failing but it really doesn't help narrow the problem down...
Next, you can use a utility like The Unarchiver to extract the .pkg file. Your scripts will need to be extracted twice by this utility.
Note: If you prefer the command line:
xar -xf my_package.pkg # extract pkg
tar -xf Scripts # extract scripts
From there, you can attempt to troubleshoot what's going wrong with the scripts.
But in my case, the only way I was able to debug the scripts were to run the package over and over echoing debug statements to a file.
For example:
# preinstall
echo "here!" >> /Users/Tom/Desktop/debug.txt
for such simple installers it is always better to use a tool to do the work for you. I usually use the Packages tool
http://s.sudre.free.fr/Software/Packages/about.html
which is free and really really good.
I understand PackageMaker is now deprecated. We're now supposed to use pkgbuild/productbuild.
However, I can't seem to find an example for creating an installer for a kext. I was hoping to build the package as part of a build step from my kext Xcode project. So any bash/script files would be great.
This answer is a seriously good guide for the general case.
For a kext specifically, after the Product -> Archive step, to generate the component plist, I found that I needed to 'cd' into the built archive package directory:
cd ~/Library/Developer/Xcode/Archives/2013-12-22/my-kext\ 22-12-2013\ 22.57.xcarchive
Then, the pkgbuild --analyze step looks like this:
pkgbuild --analyze --root ./Products/ my-kext.plist
The produced plist should contain a sensible-looking install destination for your kext under the RootRelativeBundlePath key. (typically /System/Library/Extensions/my.kext, or if codesigned and for 10.9+ it should be /Library/Extensions/my.kext) If not, fix the install location for your kext target in Xcode.
The main thing to watch out for when installing kexts is to get permissions right and to refresh the kext cache. pkgbuild seems to install the kext as root by default, so that's good. To force refreshing the kext cache, you need to update the modified time on /System/Library/Extensions (or /Library/Extensions if that's where you're installing to). You want to do this after your kext has been fully installed, so you'll need a postinstall script. Create a directory for it, e.g. ./scripts and create a file called 'postinstall' with the contents:
#!/bin/sh
touch /System/Library/Extensions
Then make it executable:
chmod +x postinstall
You can now build a generic package for your kext using:
pkgbuild --root ./Products/ --scripts ./scripts/ --component-plist my-kext.plist my-kext.pkg
For customisation, codesigning, etc., follow the instructions in catlan's linked answer - you can't beat them!