Generally speaking, you can only relocate a package (that is, install it into a different directory) that has been built with relocation in mind.
If the package supports it, it can be relocated with the command line equivalent of Installer.app
, conveniently called installer
, with option -target
(from man installer
):
The target volume is specified with the -target
parameter (-tgt
is
accepted as a synonym).
The argument to -target
is:
A volume mount point (/Volumes/HDD
), device node (/dev/disk0s5
) or volume UUID (376C4046-083E-334F-AF08-62FAFBC4E352
), for example:
installer -pkg InstallMe.pkg -target /
Any of the values returned by -dominfo
(LocalSystem
or CurrentUserHomeDirectory
), for example:
installer -pkg InstallMe.pkg -target CurrentUserHomeDirectory
(As you see, the latter command looks very promising. It would install InstallMe.pkg
in the hierarchy of the home directory of the current user.)
In our specific case, unfortunately, ActiveState's Tcl package wasn't designed to be relocated:
It doesn't return any information for -dominfo
:
$ installer -verbose -dominfo -pkg ActiveTcl-8.6.pkg
Domain information:
NoDomainsAvailable
Although the pkg
file can be successfully installed on another volume:
$ sudo installer -verbose -pkg ActiveTcl-8.6.pkg -target /Volumes/DISK2GO/
installer: Package name is ActiveState ActiveTcl 8.6.0.0.296563
installer: Installing at base path /Volumes/DISK2GO
(...)
#
installer: Writing files….....
(...)
installer: The software was successfully installed......
installer: The install was successful.
#
as can be seen here:
it doesn't work:
$ cd /Volumes/DISK2GO/usr/local/bin/
$ ./tclsh8.6
dyld: Library not loaded:
/Library/Frameworks/Tcl.framework/Versions/8.6/Tcl
Referenced from: /Volumes/DISK2GO/usr/local/bin/./tclsh8.6
Reason: image not found
Trace/BPT trap: 5
$ ./tclselect
-bash: ./tclselect: /usr/local/bin/tclsh: bad interpreter: No such file or directory
The reason is that scripts and compiled tools use and are linked to /Library/Frameworks
:
$ cd /Volumes/DISK2GO/usr/local/bin/
$ otool -L tclsh8.6
tclsh8.6:
/Library/Frameworks/Tcl.framework/Versions/8.6/Tcl (compatibility version 8.6.0, current version 8.6.0)
(...)
$ grep Library tclselect
# /Library/Frameworks
# installation. I.e. a Tcl installed in '/Library/Frameworks' and
return /Library/Frameworks/Tcl.framework/Versions
If you wish to use ActiveState's Tcl you must install the package in its default location.
And as far as I can tell, it won't conflict with the installed Tcl framework:
OS X own framework is installed in /System/Library/Frameworks/Tk.framework/
, some binaries in /usr/bin
.
ActiveState's Tcl installs in /Library/Frameworks/Tcl.framework
, /Library/Frameworks/Tk.framework
, /Library/Tcl
and /usr/local/bin
(for a full listing, double click the pkg
file and select File>ShowFiles).
Short Answer: yes.
Long Answer: Yes, but…a full answer to this question includes a technical answer and a practical concern.
First, the technical answer
You can install a .pkg or .mpkg using this syntax:
sudo installer -verboseR -pkg "/path/to/pkg/foo.mpkg"
If the installer isn't 'signed' properly, you'll need to add -allowUntrusted
sudo installer -allowUntrusted -verboseR -pkg "/path/to/pkg/foo.mpkg"
You may also need to specify where you want it installed, using -target /
(I'm not 100% certain this is required, but it's a good idea):
sudo installer -allowUntrusted -verboseR -pkg "/path/to/pkg/foo.mpkg" -target /
Now, the problem is that sudo
is going to ask you for your administrator password when you try to run installer
. If you want to automate this, you need to tell your Mac not to require your sudo
password when running the installer. To do that, you can add this line to your /etc/sudoers
file:
%admin ALL=NOPASSWD: /usr/sbin/installer
See man visudo
for instructions on editing that file.
Second, the practical concern
If you are the only person who uses your Mac, adding the above line to /etc/sudoers
is not a big deal.
However, if this is a shared Mac, then other people who are in the 'admin' group will be able to run /usr/sbin/installer
without being prompted for their password.
Also, obviously if someone gets into your 'admin' account, they too could, theoretically, cause mischief with /usr/sbin/installer
. Although I am at a loss to think of exactly what they would do, it's a trade-off of security versus convenience.
Third, a github script
I wrote pkginstall.sh to do some nice things like log the process, as well as tell you whether or not you are supposed to reboot after installing the package.
Last but not least: Automate "how?"
As far as how you want to automate the installation, that depends on more specifics of what you are trying to do. You could, for example, make a folder such as ~/Action/AutoInstallPKG/ and tell launchd
to install any .pkg or .mpkg files that are added to that folder, and then move it aside afterwards.
I have been meaning to do something like this for a long time, and so I finally put it together. You can find it at https://github.com/tjluoma/autopkginstall. Installation instructions are included at Github, so I won't repeat them here.
Best Answer
Rather than using a script to create /usr/local and its subfolders, include them as part of the package's payload. That is, create a prototype "local" folder with "bin" and "etc" subfolders, and your script and conf file in them. Set the permissions correctly (root:admin, 755 for all but the conf file, 644 or maybe 664 for that). Then create an installer package that places that whole folder structure in /usr.
Note that if /usr/local (and some subfolders and files) already exist, the installer will simply merge your package's payload with what already exists (i.e. it does exactly what you want).