FreeCAD.getHomePath() not correct on Arch linux

Having trouble installing or compiling FreeCAD? Get help here.
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Mon Oct 19, 2015 5:34 pm

When installing from freecad-git on Aur, i get wrong return on FreeCAD.getHomePath() in the python console.

I get u'/usr/' instead of u'/usr/share/freecad/ witch is where the files belonging in HomePath is residing.

This problem is somewhat mitigated by the PKGBUILD script building and installing FreeCAD by the following sed command.

Code: Select all

prepare() {
   sed -i \
      -e "46i\\\tModDir = '/usr/share/freecad/Mod'" \
      -e "50i\\\tLibDir = '/usr/lib/freecad'" \
      "${srcdir}/freecad/src/App/FreeCADInit.py"
'
This seams to fix the problem for Mod and Lib folders, but anything else that relies on FreeCAD.getHomePath() in other ways fails.

One example is PartDesign:Involutegear this fails with:

Code: Select all

Traceback (most recent call last):
  File "/usr/share/freecad/Mod/PartDesign/InvoluteGearFeature.py", line 114, in setEdit
    taskd = _InvoluteGearTaskPanel(self.Object,mode)
  File "/usr/share/freecad/Mod/PartDesign/InvoluteGearFeature.py", line 136, in __init__
    self.form=FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/PartDesign/InvoluteGearFeature.ui")
  File "<string>", line 4, in <module>
<type 'exceptions.RuntimeError'>: Cannot open file
Running the Python command 'PartDesign_InvoluteGear' failed:
Traceback (most recent call last):
  File "/usr/share/freecad/Mod/PartDesign/InvoluteGearFeature.py", line 59, in Activated
    FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name,0)")
  File "<string>", line 1, in <module>

Failed to set object 'InvoluteGear' in edit modeActive view is Unnamed : 1[*] (at 0x349d640)


It has also given me problems when trying third party modules, like pluginmanager.

Searching for where FreeCAD.getHomePath() gets it information :

Code: Select all

void Application::initConfig(int argc, char ** argv)
{
    // find the home path....
    mConfig["AppHomePath"] = FindHomePath(argv[0]);


Code: Select all

const char* Application::getHomePath(void) const
{
    return _mConfig["AppHomePath"].c_str();
}


Code: Select all

std::string Application::FindHomePath(const char* sCall)
{
    // We have three ways to start this application either use one of the both executables or
    // import the FreeCAD.so module from a running Python session. In the latter case the
    // Python interpreter is already initialized.
    std::string absPath;
    std::string homePath;
    if (Py_IsInitialized()) {
        // Note: realpath is known to cause a buffer overflow because it
        // expands the given path to an absolute path of unknown length.
        // Even setting PATH_MAX does not necessarily solve the problem
        // for sure but the risk of overflow is rather small.
        char resolved[PATH_MAX];
        char* path = realpath(sCall, resolved);
        if (path)
            absPath = path;
    }
    else {
        // Find the path of the executable. Theoretically, there could  occur a
        // race condition when using readlink, but we only use  this method to
        // get the absolute path of the executable to compute the actual home
        // path. In the worst case we simply get q wrong path and FreeCAD is not
        // able to load its modules.
        char resolved[PATH_MAX];
        int nchars = readlink("/proc/self/exe", resolved, PATH_MAX);
        if (nchars < 0 || nchars >= PATH_MAX)
            throw Base::Exception("Cannot determine the absolute path of the executable");
        resolved[nchars] = '\0'; // enfore null termination
        absPath = resolved;
    }

    // should be an absolute path now
    std::string::size_type pos = absPath.find_last_of("/");
    homePath.assign(absPath,0,pos);
    pos = homePath.find_last_of("/");
    homePath.assign(homePath,0,pos+1);

    return homePath;
}


Come this far, I am quite uncertain what would be the best solution. Replicating the Ubuntu filestructure wold probably close this issue for me, but I do not know how that would go down with other Arch users.

If anyone could see some way this could be made better, I will bring it to the Aur FreeCAD maintainer.
Need help? Feel free to ask, but please read the guidelines first
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Mon Oct 19, 2015 5:44 pm

After posting this, I realised that since the freecad binary is installed in /usr/bin/freecad
the Application::FindHomePath(const char* sCall) returns /usr/
Need help? Feel free to ask, but please read the guidelines first
wmayer
Site Admin
Posts: 11352
Joined: Thu Feb 19, 2009 10:32 am

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby wmayer » Mon Oct 19, 2015 6:59 pm

After posting this, I realised that since the freecad binary is installed in /usr/bin/freecad

Is /usr/bin/freecad a symlink or a real file? Actually it must be a symlink to the actual executable where FreeCAD is installed to.
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Mon Oct 19, 2015 7:35 pm

wmayer wrote:Is /usr/bin/freecad a symlink or a real file? Actually it must be a symlink to the actual executable where FreeCAD is installed to.


Yes, it is a symlink to /usr/bin/FreeCAD

[kjetil@Arch ~]$ ls -la /usr/bin/freecad
lrwxrwxrwx 1 root root 7 okt. 16 19:48 /usr/bin/freecad -> FreeCAD

[kjetil@Arch ~]$ ls -la /usr/bin/FreeCAD
-rwxr-xr-x 1 root root 31376 okt. 16 19:48 /usr/bin/FreeCAD
Need help? Feel free to ask, but please read the guidelines first
wmayer
Site Admin
Posts: 11352
Joined: Thu Feb 19, 2009 10:32 am

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby wmayer » Mon Oct 19, 2015 8:08 pm

Yes, it is a symlink to /usr/bin/FreeCAD

But that's not much better because it's still in /usr/bin.

If anyone could see some way this could be made better, I will bring it to the Aur FreeCAD maintainer.

One option would be to do the same as e.g. for Application::getResourceDir() where a define "RESOURCEDIR" can be set from the build system.
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Mon Oct 19, 2015 9:25 pm

Something like this?

In Application.cpp replace old function with

Code: Select all

const char* Application::getHomePath(void) const
{
#ifdef HOMEDIR
    std::string path(HOMEDIR);
    path.append("/");
    QDir dir(QString::fromUtf8(HOMEDIR));
    if (dir.isAbsolute())
        return path;
    else
        return _mConfig["AppHomePath"].c_str();
#else
    return _mConfig["AppHomePath"].c_str();
#endif
}



In CMakeList.txt i add line 95:

Code: Select all

SET(HOMEDIR "${CMAKE_INSTALL_HOMEDIR}")



In PKGBUILD i change make statment to set -DCMAKE_INSTALL_HOMEDIR:PATH="share/freecad"

Code: Select all

   cmake .. \
      -DCMAKE_INSTALL_PREFIX:PATH="/usr" \
      -DCMAKE_INSTALL_DOCDIR:PATH="share/freecad/doc" \
      -DCMAKE_INSTALL_DATADIR:PATH="share/freecad" \
      -DCMAKE_INSTALL_LIBDIR:PATH="lib/freecad" \
      -DCMAKE_INSTALL_HOMEDIR:PATH="share/freecad" \
      -DOCC_INCLUDE_DIR:PATH=/opt/opencascade/inc/ \
      -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python2 \
      -DPYSIDEUIC4BINARY:FILEPATH=/usr/bin/python2-pyside-uic \
      -DFREECAD_USE_EXTERNAL_PIVY:BOOL=ON \
      -DFREECAD_USE_PCL:BOOL=ON

   make
Need help? Feel free to ask, but please read the guidelines first
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Mon Oct 19, 2015 10:34 pm

cox wrote:Something like this?


No, needs more work, and more studying.

Thanks for your help wmayer :D
Need help? Feel free to ask, but please read the guidelines first
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Tue Oct 20, 2015 12:07 pm

Finaly
I can make involute gears and FreeCAD.getHomePath() returnes what is set in -DCMAKE_INSTALL_HOMEDIR:PATH="share/freecad"

Code: Select all

[kjetil@Arch FreeCAD]$ git diff master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9b97873..ee6d0fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,12 +92,14 @@ SET(PYCXX_SOURCE_DIR
 # used as compiler defines
 SET(RESOURCEDIR "${CMAKE_INSTALL_DATADIR}")
 SET(DOCDIR "${CMAKE_INSTALL_DOCDIR}")
+SET(HOMEDIR "${CMAKE_INSTALL_HOMEDIR}")
 
 MESSAGE(STATUS "prefix: ${CMAKE_INSTALL_PREFIX}")
 MESSAGE(STATUS "datadir: ${CMAKE_INSTALL_DATADIR}")
 MESSAGE(STATUS "docdir: ${CMAKE_INSTALL_DOCDIR}")
 MESSAGE(STATUS "includedir: ${CMAKE_INSTALL_INCLUDEDIR}")
 MESSAGE(STATUS "libdir: ${CMAKE_INSTALL_LIBDIR}")
+MESSAGE(STATUS "homedir: ${CMAKE_INSTALL_HOMEDIR}")
 
 # ==============================================================================
 # == Win32 is default behaviour use the LibPack copied in Source tree ==========
diff --git a/src/App/Application.cpp b/src/App/Application.cpp
index 868235f..0316558 100644
--- a/src/App/Application.cpp
+++ b/src/App/Application.cpp
@@ -499,7 +499,17 @@ void Application::setActiveDocument(const char *Name)
@@ -499,7 +499,17 @@ void Application::setActiveDocument(const char *Name)
 
 const char* Application::getHomePath(void) const
 {
+#ifdef HOMEDIR^M
+    std::string path(HOMEDIR);^M
+    path.append("/");^M
+    QDir dir(QString::fromUtf8(HOMEDIR));^M
+    if (dir.isAbsolute())^M
+        return path.c_str();^M
+    else^M
+        return _mConfig["AppHomePath"].c_str();^M
+#else^M
     return _mConfig["AppHomePath"].c_str();
+#endif^M
 }
 
 const char* Application::getExecutableName(void) const
diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt
index 67a777d..56cf3ae 100644
--- a/src/App/CMakeLists.txt
+++ b/src/App/CMakeLists.txt
@@ -8,6 +8,10 @@ IF(RESOURCEDIR)
     add_definitions(-DRESOURCEDIR="${RESOURCEDIR}")
 ENDIF(RESOURCEDIR)
 
+IF(HOMEDIR)
+    add_definitions(-DHOMEDIR="${HOMEDIR}")
+ENDIF(HOMEDIR)
+
 IF(DOCDIR)
     add_definitions(-DDOCDIR="${DOCDIR}")
 ENDIF(DOCDIR)
(END)
Need help? Feel free to ask, but please read the guidelines first
cox
Posts: 916
Joined: Wed Nov 26, 2014 11:37 pm

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby cox » Tue Oct 20, 2015 12:52 pm

Amidst all the celebrations i discovered another error message that I have seen before, and expected it to be solved with the fix.

Code: Select all

Cannot find icon: /usr/Mod/PartDesign/WizardShaft/WizardShaft.svg


After some more searching I found another function FreeCAD.ConfigGet("AppHomePath") witch still returns /usr/

Seams like i should have made my changes in FindHomePath(argv[0]) instead of getHomePath(void).
But, in forcing the AppHomePath away from the relation to the binary, witch the code obviously tries to enforce, I am uncertain of the consequences.

Could someone please shed some light into why the AppHomePath is related to the binary?

What is the difference between _mConfig and mConfig.
Need help? Feel free to ask, but please read the guidelines first
wmayer
Site Admin
Posts: 11352
Joined: Thu Feb 19, 2009 10:32 am

Re: FreeCAD.getHomePath() not correct on Arch linux

Postby wmayer » Tue Oct 20, 2015 5:49 pm

After some more searching I found another function FreeCAD.ConfigGet("AppHomePath") witch still returns /usr/

FreeCAD.ConfigGet("AppHomePath") should be replaced with FreeCAD.getHomePath(). There are occurrences of it in Python code.

Seams like i should have made my changes in FindHomePath(argv[0]) instead of getHomePath(void).

You can change the line

Code: Select all

mConfig["AppHomePath"] = FindHomePath(argv[0]);

to

Code: Select all

#ifdef HOMEDIR
mConfig["AppHomePath"] = HOMEDIR;
#else
mConfig["AppHomePath"] = FindHomePath(argv[0]);
#endif


Then in cmake it must be forced that HOMEDIR is an absolute path. However, FreeCAD was never designed that the sub-directories 'bin', 'doc', 'Mod', ... have different parent directories. There might still be cases where certain things don't work.

What is the difference between _mConfig and mConfig.

It's a bit weird thing but the one is a reference of the other. So they are exactly the same instance of a map.