Locating macOS significant directories
(macOS only)
Overview
To locate various significant directories in macOS you can use the native macOS Foundation function
NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);which creates a list of path strings for the specified directories in the specified domains. The list is in the order in which you should search the directories.
Note: The directory returned by this method may not exist. This method simply gives you the appropriate location for the requested directory. Depending on the application’s needs, it may be up to the developer to create the appropriate directory and any in between.
Determining where to store files
Get significant directories function
{$mode objfpc}{H+}
{$modeswitch objectivec1}
interface
Uses
...
CocoaUtils, // for NStringToString
CocoaAll; // for NSArray
...
function GetSignificantDir(DirLocation: qword; DomainMask: qword; count: byte): string;
var
paths : NSArray;
begin
paths := NSSearchPathForDirectoriesInDomains(DirLocation, DomainMask, True);
if(count < paths.count) then
Result := NSString(paths.objectAtIndex(0)).UTF8String
else
Result := '';
end;Table of Directory Locations
| Directory name | Directory Description |
|---|---|
| NSApplicationDirectory | Supported applications (/Applications) |
| NSDemoApplicationDirectory | Unsupported applications and demonstration versions |
| NSDeveloperApplicationDirectory | Developer applications (/Developer/Applications) |
| NSAdminApplicationDirectory | System and network administration applications |
| NSLibraryDirectory | Various user-visible documentation, support, and configuration files (/Library) |
| NSDeveloperDirectory | Developer resources (/Developer) |
| NSUserDirectory | User home directories (/Users) |
| NSDocumentationDirectory | Documentation |
| NSDocumentDirectory | Document directory |
| NSCoreServiceDirectory | Core services (System/Library/CoreServices) |
| NSAutosavedInformationDirectory | The user’s autosaved documents (Library/Autosave Information) |
| NSDesktopDirectory | The user’s desktop directory |
| NSCachesDirectory | Discardable cache files (Library/Caches) |
| NSApplicationSupportDirectory | Application support files (Library/Application Support) |
| NSDownloadsDirectory | The user’s downloads directory |
| NSInputMethodsDirectory | Input Methods (Library/Input Methods) |
| NSMoviesDirectory | The user’s Movies directory (~/Movies) |
| NSMusicDirectory | The user’s Music directory (~/Music) |
| NSPicturesDirectory | The user’s Pictures directory (~/Pictures) |
| NSPrinterDescriptionDirectory | The system’s PPDs directory (Library/Printers/PPDs) |
| NSSharedPublicDirectory | The user’s Public sharing directory (~/Public) |
| NSPreferencePanesDirectory | The PreferencePanes directory for use with System Preferences (Library/PreferencePanes) |
| NSApplicationScriptsDirectory | The user scripts folder for the calling application (~/Library/Application Scripts/<code-signing-id> |
| NSItemReplacementDirectory | The constant used to create a temporary directory |
| NSAllApplicationsDirectory | All directories where applications can be stored |
| NSAllLibrariesDirectory | All directories where resources can be stored |
| NSTrashDirectory | The user's trash directory |
Directory Locations
Table of Path Domains
| Domain name | Domain Description |
|---|---|
| NSUserDomainMask | The user’s home directory—the place to install user’s personal items (~). |
| NSLocalDomainMask | The place to install items available to everyone on this machine |
| NSNetworkDomainMask | The place to install items available on the network (/Network) |
| NSSystemDomainMask | A directory for system files provided by Apple (/System) |
| NSAllDomainsMask | All domains |
Path Domains
Code Examples
You can now locate various significant directories and display them as demonstrated by the code examples below.
User caches directory
procedure TForm1.MenuItem5Click(Sender: TObject);
begin
ShowMessage('User caches dir: ' + GetSignificantDir(NSCachesDirectory,NSUserDomainMask,0));
end;User trash directory
procedure TForm1.MenuItem16Click(Sender: TObject);
begin
ShowMessage('User trash dir: '
+ GetSignificantDir(NSTrashDirectory,NSUserDomainMask,0));
end;Users directory
Maybe not what you expect... this is the /Users directory :-)
procedure TForm1.MenuItem10Click(Sender: TObject);
begin
ShowMessage('Users dir: ' + GetSignificantDir(NSUserDirectory,NSLocalDomainMask,0));
end;To retrieve the current user's home directory, you need to use the NSHomeDirectory() function instead:
procedure TForm1.MenuItem11Click(Sender: TObject);
begin
ShowMessage('User''s dir: ' + NSStringToString(NSHomeDirectory));
end;BUT note that if the application is in a sandbox, this will return the application’s sandbox directory and not the current user’s home directory.
An alternative way to retrieve the current user's hime directory:
function NSUserName: CFStringRef external name '_NSUserName';
...
procedure TForm1.MenuItem22Click(Sender: TObject);
var
usernameStr: ShortString;
status: Boolean = false;
begin
status := CFStringGetPascalString(CFStringRef(NSusername),@usernameStr,255,CFStringGetSystemEncoding);
if(status = true) then
ShowMessage('Current user''s dir: ' + NSStringToString(NShomeDirectoryForUser(NSStr(usernameStr))))
else
ShowMessage('Error retrieving username');
end;All application directories
procedure TForm1.MenuItem7Click(Sender: TObject);
var
count: byte;
begin
for count := 0 to 12 do
if GetSignificantDir(NSAllApplicationsDirectory, NSAllDomainsMask, count) <> '' then
ShowMessage('Application dir ' + IntToStr(count) + ': '
+ GetSignificantDir(NSAllApplicationsDirectory,NSAllDomainsMask,count))
else
exit;
end;All user application directories
procedure TForm1.MenuItem8Click(Sender: TObject);
var
count: byte;
begin
for count := 0 to 12 do
if GetSignificantDir(NSAllApplicationsDirectory, NSUserDomainMask, count) <> '' then
ShowMessage('User application dir ' + IntToStr(count) + ': '
+ GetSignificantDir(NSAllApplicationsDirectory,NSUserDomainMask,count))
else
exit;
end;All system application directories
procedure TForm1.MenuItem9Click(Sender: TObject);
var
count: byte;
begin
for count := 0 to 12 do
if GetSignificantDir(NSAllApplicationsDirectory, NSSystemDomainMask, count) <> '' then
ShowMessage('System application dir ' + IntToStr(count) + ': '
+ GetSignificantDir(NSAllApplicationsDirectory,NSSystemDomainMask,count))
else
exit;
end;Replacements for FPC's GetAppConfigDir and GetAppConfigFile
The existing FPC GetAppConfigDir and GetAppConfigFile functions are not macOS friendly because they use the UNIX convention and not the Apple macOS convention. For example, the output from these functions:
writeLn(GetAppConfigDir(true));
writeLn(GetAppConfigDir(false));
writeLn(GetAppConfigFile(true));
writeLn(GetAppConfigFile(false));
writeLn(GetAppConfigFile(true,true));
writeLn(GetAppConfigFile(true,false));
writeLn(GetAppConfigFile(false,false));
writeLn(GetAppConfigFile(false,true));is this:
/etc/
/Users/<username>/.config/
/etc/project1.cfg
/Users/<username>/.config/project1.cfg
/etc/project1/project1.cfg
/etc/project1.cfg
/Users/<username>/.config/project1.cfg
/Users/<username>/.config/project1/project1.cfgwhereas the correct output for a macOS command line application (ie without an Application Bundle) is:
/Library/Application Support/project1/
/Users/<username>/Library/Application Support/project1/
/Library/Application Support/project1/project1.plist
/Users/<username>/Library/Application Support/project1/project1.plist
/Library/Application Support/project1/project1.plist
/Library/Application Support/project1/project1.plist
/Users/<username>/Library/Application Support/project1/project1.plist
/Users/<username>/Library/Application Support/project1/project1.plistand the correct output for a macOS GUI application (ie with an Application Bundle):
/Library/Application Support/com.company.project1/
/Users/<username>/Library/Application Support/com.company.project1/
/Library/Application Support/com.company.project1/project1.plist
/Users/<username>/Library/Application Support/com.company.project1/project1.plist
/Library/Application Support/com.company.project1/project1.plist
/Library/Application Support/com.company.project1/project1.plist
/Users/<username>/Library/Application Support/com.company.project1/project1.plist
/Users/<username>/Library/Application Support/com.company.project1/project1.plistHere are the replacement functions -- named with the addition of a 2 to the existing function names -- and with ${IFDEF}s so that they can be used in multi-platform code:
{$mode objfpc}{H+}
{$modeswitch objectivec1}
...
Uses
...
SysUtils,
CocoaAll,
Cocoautils;
...
//
// GetAppConfigDir Replacement
//
function GetAppConfigDir2(Global: Boolean): String;
{$IFDEF DARWIN}
var
bundleIdStr: String;
pathsArr : NSArray;
{$ENDIF}
begin
{$IFDEF DARWIN}
bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
if(bundleIdStr = '') then
bundleIdStr := ExtractFileName(paramstr(0)); // Handle non-bundled apps eg command line
if(Global) then
pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, True)
else
pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True);
Result := NSString(pathsArr.objectAtIndex(0)).Utf8String + '/' + bundleIdStr + '/';
{$ELSE}
GetAppConfigDir(global);
{$ENDIF}
end;
//
// GetAppConfigFile replacement
//
Function GetAppConfigFile2(Global : Boolean; SubDir : Boolean) : String;
{$IFDEF DARWIN}
var
bundleIdStr: ShortString;
appNameStr: ShortString;
pathBufferStr: String;
isAppBundle : Boolean = True;
{$ENDIF}
begin
{$IFDEF DARWIN}
bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
if(bundleIdStr = '') then
begin
bundleIdStr := ExtractFileName(paramstr(0)); // Handle non-bundled apps eg command line
isAppBundle := False;
end;
pathBufferStr := GetAppConfigDir2(Global);
if(isAppBundle) then
appNameStr := StringReplace(ExtractFileExt(bundleIdStr), '.', '', [rfReplaceAll])
else
appNameStr := extractFileName(ExcludeTrailingPathDelimiter(pathBufferStr));
if(SubDir) then
// Ignore because Apple dictates the subdir already as part of GetAppConfigDir()
;
Result := pathBufferStr + appNameStr + '.plist';
{$ELSE}
Result := GetAppConfigFile(Global, SubDir);
{$ENDIF}
end;See also
- Locating macOS app support, preferences folders
- Locating the macOS application resources directory
- Locating the macOS tmp directory
From the Free Pascal wiki, page "Locating macOS significant directories", as it stood on 2021-03-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.
Talk about this page
Nobody has opened a bench for this page yet. Sign in to open one.
