Code::Blocks Forums
Developer forums (C::B DEVELOPMENT STRICTLY!) => Development => Topic started by: afb on November 20, 2006, 09:23:51 pm
-
app#GetAppPath vs. configmanager#DetermineExecutablePath
Why do both these square wheels exist ? Should I just copy/paste ?
And unfortunately wxStandardPathsBase::Get().GetDataDir() seems
to return the wrong result in wx 2.6.3, might bug-report it for 2.8.0.
-
If we want to go the copy-and-paste route, here is a patch for wxMac:
http://www.algonet.se/~afb/wx/codeblocks-configmanagermac.patch
We might want to look into using/upgrading BinReloc for Linux, or not ?
http://autopackage.org/docs/binreloc/ (prefix.cpp/h is an old version)
-
app#GetAppPath vs. configmanager#DetermineExecutablePath
Why do both these square wheels exist ? Should I just copy/paste ?
They both exist because I did not remove the one in CodeBlocksApp hastily (not knowing where it might be used). If no other code depends on it (plugins?), we could remove/replace it, but let's not be hasty.
Formerly, the application used to set app_path at some time during startup. Before this, the value returned by ConfigManager was undefined. That was ugly, but not a big issue because we made sure we didn't use it earlier.
Now, ConfigManager makes user paths dependent on where the config file was found. That means that it does all that path initialising a lot earlier (the first time any ConfigManager function is called) and consequently needs to know app_path a lot earlier too (and perferrably not depending on the state of startup).
The Linux code in CodeBlocksApp was not very good anyway, it never really determined a path, but simply assumed ".", which may accidentially work, but often does not.
The new version tries to read /proc/self/exe (and falls back to ".") which is not perfect, but a bit better. If you know of a yet better method, please step forward. :)
And unfortunately wxStandardPathsBase::Get().GetDataDir() seems
to return the wrong result in wx 2.6.3, might bug-report it for 2.8.0.
It's exactly what was used before too, though. Only now we have if(...) return and before we had return wxPathList.FindValid(...).
Where does it return a wrong value, MacOS? Works under Windows. Have not tested under Linux myself, but nobody complained during the last 6 weeks...? :)
-
The Linux code in CodeBlocksApp was not very good anyway, it never really determined a path, but simply assumed ".", which may accidentially work, but often does not.
The code that I saw used APP_PREFIX, and if that wasn't available it used BinReloc instead. Unfortunately it used the application path instead of the application prefix, so it was still broken but I fixed that in the latest revision (appended a "/.." to it)
The new version tries to read /proc/self/exe (and falls back to ".") which is not perfect, but a bit better. If you know of a yet better method, please step forward. :)
BinReloc (http://autopackage.org/docs/binreloc/).
And unfortunately wxStandardPathsBase::Get().GetDataDir() seems
to return the wrong result in wx 2.6.3, might bug-report it for 2.8.0.
It's exactly what was used before too, though. Only now we have if(...) return and before we had return wxPathList.FindValid(...).
Where does it return a wrong value, MacOS? Works under Windows. Have not tested under Linux myself, but nobody complained during the last 6 weeks...? :)
(yes - wrong in wxMac, sorry for the lack of context)
It returns SharedSupport, which is not absolutely wrong (although intended for templates and such non-mandatory) material but we have decided on using Resources instead partly since Mandrav wanted to use share/codeblocks on all platforms...
i.e. if you ask wxWidgets it would use CodeBlocks.app/Contents/SharedSupport for resources and CodeBlocks.app/Contents/PlugIns for plugins, but we want it to use CodeBlocks.app/Contents/Resources/share/codeblocks[/plugins]
-
Why do both these square wheels exist ? Should I just copy/paste ?
They both exist because I did not remove the one in CodeBlocksApp hastily (not knowing where it might be used). If no other code depends on it (plugins?), we could remove/replace it, but let's not be hasty.
I just wanted to refactor them into one single nice solution instead...
The canonical application path retriever would use:
- GetModuleFileName for Windows
- br_find_exe for Linux (BinReloc)
- _NSGetExecutablePath for Mac OS X
-
The code that I saw...
Ah right... I must have confused the Mac (which really just sets ".") and Linux #ifdef paths there. Probably just saw the "." and turned away, saying "ugh...". :)
BinReloc (http://autopackage.org/docs/binreloc/).
(looks into code) Uses readlink instead of realpath (which is really the same, in the end), but for some reason, it's 13 kB of code? The documentation says that it also hardcodes paths on other platforms. If that's what we want...
Feel free to make one single, better solution out of it. No objections :)
Regarding SharedSupport versus Resources, does it matter so much for the moment? If it is an actual (and known) bug, chances are that it will fixed without us bothering about it at all, no? Or would you want to add a temporary hack which will be removed for 2.8.0?
-
Regarding SharedSupport versus Resources, does it matter so much for the moment? If it is an actual (and known) bug, chances are that it will fixed without us bothering about it at all, no? Or would you want to add a temporary hack which will be removed for 2.8.0?
It's not a real bug I guess, just a matter of opinion. (so I don't think they'll change)
I reimplemented it myself instead, so that it wouldn't be dependent on wx version ?
It was just that I was misleading the Mac users on where to place the resources.
i.e. just as I had finally decided on one location it transmogrified into another ;-)
For me it is perfectly fine to move to GetDataDir on all the C::B platforms.
It was just that the Don said that he wanted the extra "share/", so I complied...
-
BinReloc (http://autopackage.org/docs/binreloc/).
(looks into code) Uses readlink instead of realpath (which is really the same, in the end), but for some reason, it's 13 kB of code? The documentation says that it also hardcodes paths on other platforms. If that's what we want...
It's probably the same in the end, I just thought that someone else could maintain it :-)
-
Apparently the /proc hack might work (with variations) in BSD too, if one is lucky enough to have that filesystem mounted (seems to not be by default). Solaris has a getexecname so that should be easy. What other platforms do we have ? (I'm not sure that anything beyond Windows / Linux / Mac OS X will be supported, but...)
Why Can't We All Just Get Along ? :|
-
Feel free to make one single, better solution out of it. No objections :)
I think that I will do just that ... BinReloc is Public Domain, so I'll rip out any interesting bits.
-
Well, the most interesting bit (I think) is the 5 lines of code around readlink("/proc/self/exe") or realname, respectively. :)
If other Unix-derivates support /proc/self too, that's even better. I used the strict __linux__ instead of something more relaxed because I thougth it was a proprietary Linux feature. But actually there is no harm if we always use it, as realname will return 0 if the given location does not exist, so it is perfectly safe to just try and see if we get back a valid pointer.
Another possibility to get the install dir would be popen("which codeblocks"), but that's a lot slower than reading /proc/self, and unreliable, too (so we should probably abstain from it).
EDIT:
Btw, you said "proc hack". The proc hack is really not a hack at all, it is the one perfectly legal way of doing it. That's what proc is for, after all :)
-
Well, the most interesting bit (I think) is the 5 lines of code around readlink("/proc/self/exe") or realname, respectively. :)
Yup. BinReloc says that doesn't work for libraries, but we don't care I guess.
If other Unix-derivates support /proc/self too, that's even better. I used the strict __linux__ instead of something more relaxed because I thougth it was a proprietary Linux feature.
Apparently /proc is not mounted on FreeBSD, so it's not really useful there.
EDIT:
Btw, you said "proc hack". The proc hack is really not a hack at all, it is the one perfectly legal way of doing it. That's what proc is for, after all :)
Fair enough. I just think that fiddling around with /proc/self/exe is ugly :-)
(not the solution itself, but the need to use it in application level code...)
It's not like we really need the application path for anything as it is,
except messing around with finding the datadir and plugins relative to it...
-
It's not like we really need the application path for anything as it is,
except messing around with finding the datadir and plugins relative to it...
Does this seem to be a minor/non-important task?
-
It's not like we really need the application path for anything as it is,
except messing around with finding the datadir and plugins relative to it...
Does this seem to be a minor/non-important task?
What I meant was that if we don't need it for that task, we don't need it at all ?
So it doesn't matter much if it fails on FreeBSD, since it finds the files by prefix ?
Do you think we should lose using the BinReloc library, as Thomas suggests above ?
(his implementation is a fair bit shorter than what prefix.cpp and prefix.h are...)
-
Do you think we should lose using the BinReloc library, as Thomas suggests above ?
(his implementation is a fair bit shorter than what prefix.cpp and prefix.h are...)
binreloc is working under many unix implementations (including freebsd) while Thomas' solution only works for linux if I understood correctly?
-
Neat that BinReloc is working for FreeBSD, I know that it doesn't for Mac OS X.
Maybe we should start with using BinReloc if available (#ifdef ENABLE_BINRELOC),
and then fall back to Thomas solution for Linux and my own solution for Darwin ?
edit: Or maybe ENABLE_BINRELOC wasn't the definition to use, on second glance
that looks more like a setting to whether use binary relocation or use APP_PREFIX...
-
edit: Or maybe ENABLE_BINRELOC wasn't the definition to use, on second glance
that looks more like a setting to whether use binary relocation or use APP_PREFIX...
#ifdef SELFPATH
-
Do you think we should lose using the BinReloc library, as Thomas suggests above ?
(his implementation is a fair bit shorter than what prefix.cpp and prefix.h are...)
binreloc is working under many unix implementations (including freebsd) while Thomas' solution only works for linux if I understood correctly?
There is no big magic in "many unix implementations". Binreloc returns a "hardcoded path" when /proc/self does not work, according to its documentation. That's what my implementation does too. In fact, "hardcoded path" means ".", because that's all you can really do if /proc fails. This is a hack which fails under many circumstances.
Remember, Unix offers no way to determine a file's location or name from its inode (or an application's location from its image) as there may be an arbitrary number hard links (and those may even be added and removed while the program is running). /proc/self is a notable exception because it points to the FS entry that was used to launch the executable.
-
/proc is indeed empty on FreeBSD (at least on FreeBSD 6.1). So I don't see how BinReloc can "work" there either ? It does have a /usr/compat/linux/proc/self/exe, but that's probably not part of the core...
So since we need special cases for Windows, Mac OS X, FreeBSD, Solaris - I guess that means that the "many unix implementations" are probably the same as Linux in practice anyway ? :)
-
Probably :)
The question is what to make of it, though. We can always try to read /proc/self, there is no harm -- if it fails, we know it. However, if it fails, we have to use something else.
We could use ".", that works in many cases, but does not work in many other cases. We could hardcode some platform-dependent path like /usr/local/bin, but that does not work in all cases, either. We could use the prefix given by ./configure's --prefix, but that still does not work in all cases.
The problem with hardcoding an absolute path is that Code::Blocks will be bound to that one location. Unluckily, "." is not much better, it works in arbitrary locations, but depends on the mode of execution... :(
What to do?
-
There is no big magic in "many unix implementations". Binreloc returns a "hardcoded path" when /proc/self does not work, according to its documentation. That's what my implementation does too. In fact, "hardcoded path" means ".", because that's all you can really do if /proc fails. This is a hack which fails under many circumstances.
We do have *BSD users and it does work for them. Heck, we had even got a patch for binreloc to work on *BSD.
Admittedly, I have not looked into binreloc's code but it was safe to assume that it works, since *BSD users were saying so?
We could use ".", that works in many cases, but does not work in many other cases. We could hardcode some platform-dependent path like /usr/local/bin, but that does not work in all cases, either. We could use the prefix given by ./configure's --prefix, but that still does not work in all cases.
Hardcoding is out of the question.
Why, all of the sudden, do you want to change things regarding this matter? It does work as it is anyway, AFAIK. And if there are cases which don't work and there is no OS-provided workaround available, C::B already allows you to set the data path in two distinct ways: 1) by adding a command-line option or 2) by setting an environment variable.
The bottom line is that C::B, most of the times, will determine its path automatically but if it doesn't it can be directed to it by the user.
-
There is no big magic in "many unix implementations". Binreloc returns a "hardcoded path" when /proc/self does not work, according to its documentation. That's what my implementation does too. In fact, "hardcoded path" means ".", because that's all you can really do if /proc fails. This is a hack which fails under many circumstances.
We do have *BSD users and it does work for them. Heck, we had even got a patch for binreloc to work on *BSD.
Admittedly, I have not looked into binreloc's code but it was safe to assume that it works, since *BSD users were saying so?
I think the patches were only to have it compile without throwing warning/errors... ? (don't think it "works")
The FreeBSD ports I've seen do a: #define APP_PREFIX "/usr/local", and don't use binary relocation (I believe Linux has the same default, but haven't tried using binreloc on Linux yet) We used to do the same in the Mac OS X wrapper, before I ported app/configmanager (i.e. set a prefix explicitly, by using the --prefix option to codeblocks).
Using the BinReloc "library" or Thomas's readlink("/proc/self/exe") should amount to the same thing in the end, but will only work reliably on Linux. All I was asking was that app.cpp and configmanager.cpp should use the same code to determine prefix/datadir ? But I can test the --enable-binreloc version on Linux, and see if it relocates OK.
-
We do have *BSD users and it does work for them. Heck, we had even got a patch for binreloc to work on *BSD.
It's nice that it works for them :) For your reference, the code that we use looks like this:
base = wxString(SELFPATH,wxConvUTF8);
if (base.IsEmpty())
base = _T(".");
#define SELFPATH (br_thread_local_store (br_locate ((void *) "")))
char *br_locate (void *symbol)
{
char line[5000];
FILE *f;
char *path;
br_return_val_if_fail (symbol != NULL, (char*)NULL);
f = fopen ("/proc/self/maps", "r");
if (!f)
return (char*)NULL;
while (!feof (f))
... <more code>
#define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "..."); return val;}
I'm so happy it works nicely for BSD. :)
Hardcoding is out of the question.
That's unfortunate, because that's what we do now.
Why, all of the sudden, do you want to change things regarding this matter?
I don't want to change things regarding this matter at all. Heck, I could imagine more pleasant things to do.
As you asked for, I was making user plugin paths depending on the location of the config file found. The ConfigManager instances know nothing about the underlying file, that's handled by the related factory class.
Thus, the executable's path (and other paths) must be known a lot earlier now, this can no longer wait until the application eventually figures it out and sets it. Therefore, I implemented something which I thought should work.
In the end, as binreloc depends on /proc/self too, my 6 lines of code do not change any single thing, except they are 6 lines instead of 550 lines...
-
AFAIK: FreeBSD ports will find stuff relative to the $PREFIX it is compiled for (default /usr/local but could be /opt). I don't think we need any binary relocation other than that, i.e. like AutoPackage's BinReloc does it - so that you can move the binaries ? But I only know what I read in the FreeBSD Porter's Handbook (http://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/), I'm not really a BSD user.
I will be happy to test on PC-BSD 1.2 (based on FreeBSD 6.1). But /proc is empty, so that does not work.
-
For your reference, the code that we use looks like this:
Admittedly, I have not looked into binreloc's code
Thanks for posting the code here or else I couldn't read it, should I wanted to...
I'm so happy it works nicely for BSD. :)
And thanks for the sarcasm too.
Hardcoding is out of the question.
That's unfortunate, because that's what we do now.
So we are hardcoding /usr/local, /opt or whatever? Strange, I haven't noticed... What revision did this happen in and who did it?
Why, all of the sudden, do you want to change things regarding this matter?
I don't want to change things regarding this matter at all.
All I know is that there was no need to discuss this issue (i.e. it was a non-issue, we had no complaints so far) up to now and suddenly I see a two pages long topic on the subject. I just want to know what triggered this.
-
But I can test the --enable-binreloc version on Linux, and see if it relocates OK.
Tested on Ubuntu, interestingly the default installation did not work (it looked in /usr/local/share/codeblocks, while the file had been installed in /usr/share/codeblocks). However, if you copied all of it over from /usr to /opt/codeblocks - then it found the files in /opt/codeblocks/share/codeblocks just fine, so binreloc seems to be working fine on Linux.
-
All I know is that there was no need to discuss this issue (i.e. it was a non-issue, we had no complaints so far) up to now and suddenly I see a two pages long topic on the subject. I just want to know what triggered this.
Thomas did a refactoring of configmanager.cpp, that broke the wxMac support I added.
And it featured a reimplementation of the same code that was in app.cpp, so I asked...
-
Just for the record here is what I found the default locations to be:
Code::Blocks
- wxMSW:
@executable_path/share/CodeBlocks
@executable_path/share/CodeBlocks/plugins - wxGTK:
$PREFIX/share/codeblocks
$PREFIX/share/codeblocks/plugins - wxMac:
CodeBlocks.app/Contents/Resources/share/codeblocks
CodeBlocks.app/Contents/Resources/share/codeblocks/plugins
wxStandardPaths (GetDataDir and GetPluginsDir)
- wxMSW:
@executable_path
@executable_path - wxGTK:
$PREFIX/share/codeblocks
$PREFIX/lib/codeblocks - wxMac:
CodeBlocks.app/Contents/SharedSupport
CodeBlocks.app/Contents/PlugIns
Where "@executable_path" is the directory where the .exe is located.
-
So we are hardcoding /usr/local, /opt or whatever? Strange, I haven't noticed...
Yes, and yes.
But anyway, I am sick of endlessly justifying every 6 lines of code that I ever wrote. Do whatever you want, and if you think SELFPATH is so much of a better solution then for pity's sake use it...
-
Should we add a second function to just get the app prefix ?
The "/usr/local/bin/.." works fine, but looks a bit strange...
-
So we are hardcoding /usr/local, /opt or whatever? Strange, I haven't noticed...
Yes, and yes.
But anyway, I am sick of endlessly justifying every 6 lines of code that I ever wrote. Do whatever you want, and if you think SELFPATH is so much of a better solution then for pity's sake use it...
I didn't expect this kind of answer, not based on my questions on why some things have changed like this :roll:.
I really don't give a damn if binreloc is used or not. What I care about is for things to work. If you believe your solution is better/smaller/faster, just use it. But don't react like that when I ask questions about it because I 'm trying to understand why some things stopped working. And if I don't understand then somebody else will have to fix them. And that somebody will have to be you because it's only you who know what has changed.
If that's what you want, here's a bug report for you: This (http://forums.codeblocks.org/index.php?topic=4523.msg35882#msg35882) used to work fine and now it's broken...
PS: next time please put a note in your forum posts stating whether I am allowed to ask anything about it or not. Strangely enough I thought that I had that right but now it seems I was wrong...
-
Did anyone test revision 3245 and newer on Linux with '-prefix=/opt/codeblocks' or something similar as parameter for the configure-script?
Because Code::Blocks failes to find its ressources and plugins here. It tries to find them in '/usr/local/share/codeblocks' which obviously does not exist here. It should use '/opt/codeblocks' instead.
-
Did anyone test revision 3245 and newer on Linux with '-prefix=/opt/codeblocks' or something similar as parameter for the configure-script?
Because Code::Blocks failes to find its ressources and plugins here. It tries to find them in '/usr/local/share/codeblocks' which obviously does not exist here. It should use '/opt/codeblocks' instead.
It probably does not work with earlier revisions, either. Have you tried --prefix=/opt ever since 3194?
I would be very surprised if it worked using 3244.
-
I never built Code::Blocks without this option. I'm not quite sure what revisions I used recently, but at least revision 3230 was working for me (used this one to find the problem with the splash screen on Linux).
-
I never built Code::Blocks without this option. I'm not quite sure what revisions I used recently, but at least revision 3230 was working for me (used this one to find the problem with the splash screen on Linux).
That's true. I happen to have 3230 around (in linux) and --prefix works fine with it.
-
Well, that's magic then, because it cannot work.
For --prefix= to work, you need to call wxStandardPathsBase::SetInstallPrefix(), which I forgot to add in 3194.
Plugins and resources are found (or not found) using wxStandardPathsBase::Get().GetDataDir() since 3194. This has not changed in 3245, and the changes in 3245 are more or less unrelated to the actual plugin/resource paths (short of a ?: that sets user = global in "relocated" mode).
My much-discussed /proc/self code affects GetAppPath(), but not the other ones.
wxStandardPathsBase::Get().GetDataDir() returns a global variable that you can set using above function (which we aren't doing), and which it fills it when empty. For that, it appends the application's name to wxStandardPathsBase::Get().GetPrefix().
That latter function, yes you guessed it, uses readlink("/proc/self/exe") to get the application's location, removes everything after the last "/bin/", and finally hardcodes /usr/local/ as a fallback in case anything goes wrong.
-
No magic whatsoever. The app sets the datapath and this was honoured before whether you believe it or not.
With the latest changes though, ConfigManager::InitPaths() is called only when the first ConfigManager::GetFolder() is made, which in turn overwrote the datapath setting with whatever ConfigManager felt was right. There, that was the actual problem.
-
I'll continue to patch both versions (GetAppPath/DetermineExecutablePath) for Darwin/Solaris.