Writing installers for wxWidgets applications |
Note that you should install any DLLs that are needed by your application, and if you use VC++ this will probably include msvcrt.dll and maybe msvcirt.dll. You can determine the DLL dependencies of your application using Steve Miller's Dependency Walker.
Some people prefer to write a shell script which may still invoke RPM. A good wxWidgets project would be to write a font-end installer builder that would write RPM spec files and/or a friendly shell script. An example shell script to put on the wxWidgets web site would be welcome.
The following is a list of known Linux or generic Unix installers.
The following articles may be of interest to those writing their own Linux application installer.
For Classic (OS 9 and below), you can use InstallerMaker from Aladdin or Installer VISE from Mindvision.
Robert Roebling says:
"I put the whole dir into Alladin StuffIt (which you need to buy) and make the wxSomething.sit file into a wxSomething.sit.bin file with Alladin later, since the latter step is required for Netscape users downloading such an archive."
Brian Victor says:
"I'd like to point out that you can also use Alladin's DropStuff, which is shareware, to create .sit archives.
In OSX, it seems to be popular to create disk images of application bundle with directions to just drag the bundle into one's hard drive. Bundles make that really clean and easy. Usually these disk images are compressed with Stuffit or DropStuff.
Also, Apple has its own packaging system for OSX, which helps take care of things like click-through licensing, getting administrator (i.e., root) privileges, and probably dependencies also. Such packages have a .dpkg suffix."
The following is a list of known Mac installers.
#!/bin/sh # filled-in by the installer script or whatever APPDIR=/home/user/mydir # set LD_LIBRARY_PATH and other stuff here... $APPDIR/bin/myapp.bin
Well, I've read the posts about finding the path. All seemed pretty good, but maybe this one is better :-)
There is a way to detect in a running program where the absolute path of that running program is. This is done in one tool that I know of: mpatrol.
mpatrol runs on a variety of unixes (it's a memory profiler/bounds checker) and has a pretty complicated bit of coding to correctly detect the runtime program's path. It doesn't use path traversing, just stack manipulations and on easy platforms /proc. The code for the function progname() (in memory.cc) is nasty to say the least. mpatrol currently runs on: AIX, DG/UX, DRS/NS, DYNIX/ptx, FreeBSD, HP/UX, IRIX, Linux, LynxOS, SINIX, Solaris, UnixWare, AmigaOS and Windows NT.
It's under LGPL, so you can make it a linked library and just call what you want. Anyways, the function is called progname() and returns the char * path. It's useful in my programs, because when they crash I can have gigs of stuff in memory and saving core files that size sucks, so I trap, and look up the program path and then start gdb on the program while it's running so that I can see where the problem was without resorting to core files.
On Mac Classic, argv is not used. The method of getting this information is long and convoluted, involves calling GetCurrentProcess() and GetProcessInformation(), and then taking the processAppSpec field of the returned structure and converting it into an absolute path.
So here's a more "robust" and more universal solution (tested, barring any further required #includes):
#ifdef __WXMAC__ # ifdef __DARWIN__ # include# else # include # endif # include "wx/filename.h" #endif wxString ::GetExecutablePath() { static bool found = false; static wxString path; if (found) return path; else { #ifdef __WXMSW__ char buf[512]; *buf = '\0'; GetModuleFileName(NULL, buf, 511); path = buf; #elif defined(__WXMAC__) ProcessInfoRec processinfo; ProcessSerialNumber procno ; FSSpec fsSpec; procno.highLongOfPSN = NULL ; procno.lowLongOfPSN = kCurrentProcess ; processinfo.processInfoLength = sizeof(ProcessInfoRec); processinfo.processName = NULL; processinfo.processAppSpec = &fsSpec; GetProcessInformation( &procno , &processinfo ) ; path = wxMacFSSpec2MacFilename(&fsSpec); #else wxString argv0 = wxTheApp->argv[0]; if (wxIsAbsolutePath(argv0)) path = argv0; else { wxPathList pathlist; pathlist.AddEnvList(wxT("PATH")); path = pathlist.FindAbsoluteValidPath(argv0); } wxFileName filename(path); filename.Normalize(); path = filename.GetFullPath(); #endif found = true; return path; } }
And finally, here's a function that solves the problem for me (Julian Smart):
// Find the absolute path where this application has been run from. // argv0 is wxTheApp->argv[0] // cwd is the current working directory (at startup) // appVariableName is the name of a variable containing the directory for this app, e.g. // MYAPPDIR. This is checked first. wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName) { wxString str; // Try appVariableName if (!appVariableName.IsEmpty()) { str = wxGetenv(appVariableName); if (!str.IsEmpty()) return str; } #if defined(__WXMAC__) && !defined(__DARWIN__) // On Mac, the current directory is the relevant one when // the application starts. return cwd; #endif if (wxIsAbsolutePath(argv0)) return wxPathOnly(argv0); else { // Is it a relative path? wxString currentDir(cwd); if (currentDir.Last() != wxFILE_SEP_PATH) currentDir += wxFILE_SEP_PATH; str = currentDir + argv0; if (wxFileExists(str)) return wxPathOnly(str); } // OK, it's neither an absolute path nor a relative path. // Search PATH. wxPathList pathList; pathList.AddEnvList(wxT("PATH")); str = pathList.FindAbsoluteValidPath(argv0); if (!str.IsEmpty()) return wxPathOnly(str); // Failed return wxEmptyString; }
On Unix, you can compile wxWidgets with the --disable-shared configure option, so that wxGTK and GTK+ will be linked into the application. Although your executable will be quite big, you will save on the hassles of installing shared libraries on your user's machine.