How to use pkgbuild to create a kext installer from within Xcode - xcode

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!

Related

How can i create a .pkg mac installer for my binary?

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.

Mac installer overwrites ALL copies of file

I’m having an odd issue where my installer properly overwrites the previously installed app, but then overwrites the app in my build directory.
My installer build looks like this:
mkdir /tmp/foo
cp -R ~/Projects/MyApp/Builds/MacOSX/build/Release/MyApp.app /tmp/foo
pkgbuild --quiet --analyze --root /tmp/foo/ MyApp.plist
pkgbuild --quiet --root /tmp/foo/ \
--component-plist MyApp.plist \
--identifier com.mycompany.myapp \
--version $VERSION \
--install-location "/Applications" \
MyApp.pkg
productbuild --quiet --distribution "./Distribution.xml" \
--package-path "./" --resources "./Resources" \
--sign "Developer ID Installer: My LLC" "MyApp Installer.pkg"
Now, this works…it installs the app in the /Applications folder as I’d expect. But I was noticing some issues with my next Xcode build. After some investigating, I noticed that my build folder looked like this after the Xcode build and before running the installer:
drwxr-xr-x# 3 me staff 96 Jul 11 23:15 My.app
…and like this, AFTER running the installer:
drwxr-xr-x 3 root wheel 96 Jul 11 23:44 My.app
Somehow, the owner of my app had changed. I double checked everything and didn’t see anything that touched my build folder. But then I checked the installer log and found this mysterious line:
PackageKit: Applications/MyApp.app relocated to
Users/me/Projects/MyApp/Builds/MacOSX/build/Release/MyApp.app
After some googling, others have speculated that the installer overwrites ANY copy of the app it finds anywhere on the drive…not just the one in the folder you tell it. It makes some sense…if I delete that copy of my app in the build folder, the installer doesn’t create a new one. It only overwrites it if it’s there.
While this isn’t a huge problem, it’s somewhat problematic as it changes the owner of the file which prevents the next build from working.
Has anyone else run into this issue? Is there some option for the installer to NOT overwrite EVERY copy of the installed app?
The Installer has a few features that allow it to locate application bundles that have moved in the file system. Inside your compiled .pkg, have a look at the PackageInfo and Distribution files, and see if you see any <locator> tags. The <locator> tag is defined at the link below, and is one of the main ways to enable this sort of thing.
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW15
Another possibility is that you may have a <bundle> element with the search property set, as documented here:
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW36
If you want to easily inspect the internal structure of your compiled package, you can use Pacifist to do that fairly easily. (disclaimer: I'm the author of Pacifist)
It's just a hunch, but I wonder if this can be solved by forgetting the current installs of your app by dropping the installation receipts like this:
sudo pkgutil --forget com.mycompany.myapp.pkg
You can get a list of all package receipts on your machine like this:
sudo pkgutil --pkgs
The reason I have this hunch is because I think the install locations might be stored in the receipts. Therefore causing the machine to "forget" (delete) where the packages are might make it so the installer has to install at the specified location specified by the package. I fully admit this is a WAG (wild-ass guess).

Create .pkg installer with bare executable

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

How to debug Mac OS X pkg?

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.

File Ownership Modification by productbuild and pkgbuild

I am trying to create an installer for a Java app on Mac OS 10.8.4. The app runs fine, and I can install it without a hitch from a zip file. I can create a .pkg installer with either productbuild or pkgbuild. I can also install either of the installer .pkg file successfully, however the app does not run properly due to the fact that both packaging programs change the ownership of a data directory and its subordinate files and subdirectories from user to root. I install this data directory in the Resources directory of the .app bundle, and the first time the program executes, it moves the data directory to /Users/user/Library/Application Support. I tried using the --ownership preserve and --ownership preserve-other options with pkgbuild to no avail. The only way I have been able to install and execute properly is via the zip file, since it leaves file ownership alone. Here is the pkgbuild command I am using:
pkgbuild --ownership preserve --component ./myApp.app ./myApp-installer.pkg
My questions are:
How can I force pkgbuild to honor my --ownership preserve option?
Is it possible to build a separate data-only package with user ownership and destined for the user area and merge it with the executable package via the --synthesize option of pkgbuild? if yes, could someone show me how to build such a data-only package?
I know it is quite old, I'll just answer in case someone else needs the answer.
What I usually do, is that I have a shell script which creates the .pkg file for me. In that script I set all the file permissions and ownership before packaging. Here is an example:
NAME="PKGFILENAME"
IDENTIFIER="com.pkg.APPNAME"
VERSION="1.0.0"
INSTALL_LOCATION="PATH_TO_WHERE_THE_FILES_SHOULD_BE_COPIED_ON_USERS_MACHINE"
ROOT_LOCATION="PATH_TO_WHERE_FILES_ARE_ON_YOUR_MASCHINE"
# Remove any unwanted .DS_Store files.
find "$ROOT_LOCATION" -name '*.DS_Store' -type f -delete
# put any command for changing the ownership or permissions here
chmod -R +r "$ROOT_LOCATION"
# Build package.
/usr/bin/pkgbuild \
--root "$ROOT_LOCATION" \
--install-location "$INSTALL_LOCATION" \
--identifier "$IDENTIFIER" \
--version "$VERSION" \
"$NAME.pkg"
save this something in a file like create-my-package.sh and run this in command line.

Resources