Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Find path to FreeCAD.so when importing from external python on MacOS #624

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 26 additions & 19 deletions src/App/Application.cpp
Expand Up @@ -2281,28 +2281,35 @@ std::string Application::FindHomePath(const char* sCall)

std::string Application::FindHomePath(const char* call)
{
uint32_t sz = 0;
char *buf;

_NSGetExecutablePath(NULL, &sz); //function only returns "sz" if first arg is to small to hold value
buf = (char*) malloc(++sz);

if (_NSGetExecutablePath(buf, &sz) == 0) {
char resolved[PATH_MAX];
char* path = realpath(buf, resolved);
free(buf);

if (path) {
std::string Call(resolved), TempHomePath;
std::string::size_type pos = Call.find_last_of(PATHSEP);
TempHomePath.assign(Call,0,pos);
pos = TempHomePath.find_last_of(PATHSEP);
TempHomePath.assign(TempHomePath,0,pos+1);
return TempHomePath;
// If Python is intialized at this point, then we're being run from
// MainPy.cpp, which hopefully rewrote argv[0] to point at the
// FreeCAD shared library.
if (!Py_IsInitialized()) {
uint32_t sz = 0;
char *buf;

_NSGetExecutablePath(NULL, &sz); //function only returns "sz" if first arg is to small to hold value
buf = new char[++sz];

if (_NSGetExecutablePath(buf, &sz) == 0) {
char resolved[PATH_MAX];
char* path = realpath(buf, resolved);
delete [] buf;

if (path) {
std::string Call(resolved), TempHomePath;
std::string::size_type pos = Call.find_last_of(PATHSEP);
TempHomePath.assign(Call,0,pos);
pos = TempHomePath.find_last_of(PATHSEP);
TempHomePath.assign(TempHomePath,0,pos+1);
return TempHomePath;
}
} else {
delete [] buf;
}
}

return call; // error
return call;
}

#elif defined (FC_OS_WIN32)
Expand Down
7 changes: 5 additions & 2 deletions src/App/Application.h
Expand Up @@ -336,9 +336,12 @@ class AppExport Application
static void ParseOptions(int argc, char ** argv);
/// checks if the environment is allreight
//static void CheckEnv(void);
// search for the home path
/// Search for the FreeCAD home path based on argv[0]
/*!
* There are multiple implementations of this method per-OS
*/
static std::string FindHomePath(const char* sCall);
/// print the help massage
/// Print the help message
static void PrintInitHelp(void);
/// figure out some things
static void ExtractUserPath();
Expand Down
78 changes: 68 additions & 10 deletions src/Main/MainPy.cpp
Expand Up @@ -128,21 +128,79 @@ extern "C"
argv[0][PATH_MAX-1] = '\0'; // ensure null termination
// this is a workaround to avoid a crash in libuuid.so
#elif defined(FC_OS_MACOSX)
uint32_t sz = 0;
char *buf;

_NSGetExecutablePath(NULL, &sz);
buf = (char*) malloc(++sz);
int err=_NSGetExecutablePath(buf, &sz);
if (err != 0) {
// The MacOS approach uses the Python sys.path list to find the path
// to FreeCAD.so - this should be OS-agnostic, except these two
// strings, and the call to access().
const static char libName[] = "/FreeCAD.so";
const static char upDir[] = "/../";

char *buf = NULL;

PyObject *pySysPath = PySys_GetObject("path");
if ( PyList_Check(pySysPath) ) {
int i;
// pySysPath should be a *PyList of strings - iterate through it
// backwards since the FreeCAD path was likely appended just before
// we were imported.
for (i = PyList_Size(pySysPath) - 1; i >= 0 ; --i) {
char *basePath;
PyObject *pyPath = PyList_GetItem(pySysPath, i);
long sz = 0;

#if PY_MAJOR_VERSION >= 3
if ( PyUnicode_Check(pyPath) ) {
// Python 3 string
basePath = PyUnicode_AsUTF8AndSize(pyPath, &sz);

}
#else
if ( PyString_Check(pyPath) ) {
// Python 2 string type
PyString_AsStringAndSize(pyPath, &basePath, &sz);

} else if ( PyUnicode_Check(pyPath) ) {
// Python 2 unicode type - explicitly use UTF-8 codec
PyObject *fromUnicode = PyUnicode_AsUTF8String(pyPath);
PyString_AsStringAndSize(fromUnicode, &basePath, &sz);
Py_XDECREF(fromUnicode);
}
#endif // #if/else PY_MAJOR_VERSION >= 3
else {
continue;
}

if (sz + sizeof(libName) > PATH_MAX) {
continue;
}

// buf gets assigned to argv[0], which is free'd at the end
buf = (char *)malloc(sz + sizeof(libName));
if (buf == NULL) {
break;
}

strcpy(buf, basePath);

// append libName to buf
strcat(buf, libName);
if (access(buf, R_OK | X_OK) == 0) {

// The FreeCAD "home" path is one level up from
// libName, so replace libName with upDir.
strcpy(buf + sz, upDir);
buf[sz + sizeof(upDir)] = '\0';
break;
}
} // end for (i = PyList_Size(pySysPath) - 1; i >= 0 ; --i) {
} // end if ( PyList_Check(pySysPath) ) {

if (buf == NULL) {
PyErr_SetString(PyExc_ImportError, "Cannot get path of the FreeCAD module!");
return;
}

argv[0] = (char*)malloc(PATH_MAX);
strncpy(argv[0], buf, PATH_MAX);
argv[0][PATH_MAX-1] = '\0'; // ensure null termination
free(buf);
argv[0] = buf;
#else
# error "Implement: Retrieve the path of the module for your platform."
#endif
Expand Down