14

I've written a GTKmm application and I'm trying to create some OS X enhancements. I'd like to store my configuration file in the Application Support/myApp folder, however, I can't figure out the proper way to locate this folder.

I've tried looking through the Core Foundation library (that I'm using to get my myApp.app path) but I can't find anything.

Richard Slater
  • 6,313
  • 4
  • 53
  • 81
Brandon
  • 668
  • 8
  • 22
  • the good solution is a Objective-C wrapper like the one recommended here: https://stackoverflow.com/questions/36634632/accessing-standard-directories-on-os-x-with-c (wrapper around (NSURL*)applicationDataDirectory from https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html) – Liviu Jun 22 '18 at 13:47

5 Answers5

11

Proper way to do it in C/C++:

#include <CoreServices/CoreServices.h>

FSRef ref;
OSType folderType = kApplicationSupportFolderType;
char path[PATH_MAX];

FSFindFolder( kUserDomain, folderType, kCreateFolder, &ref );

FSRefMakePath( &ref, (UInt8*)&path, PATH_MAX );

// You now have ~/Library/Application Support stored in 'path'

Naturally, those are very old APIs and their use is no longer recommended by Apple. Despite that it gets the job done if you want to avoid Objective-C completely in your codebase.

Richard Slater
  • 6,313
  • 4
  • 53
  • 81
Julio Gorgé
  • 10,056
  • 2
  • 45
  • 60
  • 1
    #include and I had to use PATH_MAX instead of MAX_PATH. – jhasse Jan 10 '12 at 00:04
  • But that API is considered deprecated. You won't be able to put your app to Mac App store. Use Objective-C++ wrapper instead. – Alexander Shishenko Mar 16 '16 at 21:11
  • @AlexanderShishenko: Maybe you're confusing deprecated APIs and **private** APIs? AFAIK, Apple isn't going to reject your app because you use deprecated APIs (in and of themselves), but they could reject it if you use undocumented/private APIs. http://stackoverflow.com/q/7909986/277952 – NSGod Apr 15 '16 at 16:07
  • Compile fails on Xcode 11: 'FSFindFolder' is deprecated: first deprecated in macOS 10.8 – Pavel Chuchuva Dec 11 '20 at 05:33
3

It appears that the function to use for this is NSSearchPathForDirectoriesInDomains (or some other functions listed on the same page) with NSApplicationSupportDirectory as the argument.

Jeremiah Willcock
  • 30,161
  • 7
  • 76
  • 78
  • 3
    Yes, but I cannot figure out how to use that in C++. The Cocoa.h file is written in Obj-C so I can't include it in my C++ app. – Brandon Feb 26 '11 at 14:42
  • 1
    @baubie: Could you write an Objective C file that wraps the API? It does appear there is a Carbon equivalent to the function, `FindFolder`, but it is marked as legacy (http://developer.apple.com/legacy/mac/library/documentation/Carbon/Reference/Folder_Manager/folder_manager.pdf) – Jeremiah Willcock Feb 26 '11 at 19:26
  • There is a wrapper in one of the answers from here: https://stackoverflow.com/questions/36634632/accessing-standard-directories-on-os-x-with-c – Liviu Jun 22 '18 at 13:47
2

In BSD Unix, included in OS-X, you can get the home directory of the user running the program with this:

struct passwd *p = getpwuid(getuid());  /* defined in pwd.h, and requires sys/types.h */ 
char *home = p->pw_dir;

Using this, you can then construct the path using this in place of ~

char *my_app_name = "WHATEVER";
char app_support[MAXPATHLEN];  /* defined in sys/param.h */
snprintf(app_support,MAXPATHLEN,"%s/Library/Application Support/%s", home, my_app_name);
  • 7
    Apple advices against hardcoding the `~/Library/Application Support/` path. For one thing, it will not work with application sandboxing in their newer OSes. – Daniel Sep 07 '12 at 22:44
  • 2
    @Aeyoun - Do you have a link to what _is_ recommended for getting this path? – Jesse Chisholm Oct 17 '17 at 18:00
1

A solution that is not deprecated

#include <sysdir.h>  // for sysdir_start_search_path_enumeration
#include <glob.h>    // for glob needed to expand ~ to user dir


std::string expandTilde(const char* str) {
    if (!str) return {};

    glob_t globbuf;
    if (glob(str, GLOB_TILDE, nullptr, &globbuf) == 0) {
        std::string result(globbuf.gl_pathv[0]);
        globfree(&globbuf);
        return result;
    } else {
        throw std::exception("Unable to expand tilde");
    }
}

std::string settingsPath(const char* str) {
    char path[PATH_MAX];
    auto state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_APPLICATION_SUPPORT,
                                                      SYSDIR_DOMAIN_MASK_USER);
    if ((state = sysdir_get_next_search_path_enumeration(state, path))) {
        return expandTilde(path);
    } else {
        throw std::exception("Failed to get settings folder");
    }
}

Peter
  • 111
  • 3
0

This is not application support but you probably don't want to store files there anyways. Instead use the directory that you get from calling "HOME":

You can use the C-function getenv: char *home = getenv("HOME");

and to get the C++ string use: string(home)