osutil.inc - GetAppConfigDir() Global and other puzzlements lazarus / 64-FPC development ---------------------------------------------------------------------- trev · 2020-05-28 13:26 Background: I'm trying to come up with a patch for macOS so that the "correct" path for GetAppConfigDir is returned (https://bugs.freepascal.org/view.php?id=20706 - ignore the function proposed there as it uses the File Manager API which is deprecated in macOS 10.8 and later). From osutil.inc: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function DGetAppConfigDir(Global : Boolean) : String; begin  Result:=ExcludeTra ilingPathDelimiter(ExtractFilePath(ParamStr(0)));end;  Where does the Global boolean get actioned? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i { ---------------------------------------------------------------------    Fallback implementations for AppConfigDir implementation.  --------- ------------------------------------------------------------}{ If a particular OS does it different: - set the HAVE_OSCONFIG define before including sysutils.inc. - implement the functions. Default config assumes a DOS-like configuration.} {$ifndef HAS_OSCONFIG}Function GetAppConfigDir(Global : Boolean) : String; begin  Result:=DGetAppConfigDir(Global);end;  1) Is the HAVE_OSCONFIG in the comment wrong as the code uses HAS_OSCONFIG ? 2) How to specify darwin? Obviously {$if define(darwin)} would do it, but in the context of using HAS/HAVE_OSCONFIG how does one do it? I couldn't see any examples in the code. I'm guessing that in sysutils.inc: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$if define(darwin)}Function GetAppConfigDir(Global : Boolean) : String;begin  // fill in bodyend; Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String; begin // fill in bodyend; {$define HAS_OSCONFIG}{$endif darwin} { OS utility code }{$i osutil.inc}  Am I close? 3) What does "Default config assumes a DOS-like configuration." mean? Still in osutil.inc, should not: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  in fact be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function DGetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  That is, the D prefix is missing on the function definition? ---------------------------------------------------------------------- PascalDragon · 2020-05-28 14:54 Quote from: trev on May 28, 2020, 03:26:34 pmBackground: I'm trying to come up with a patch for macOS so that the "correct" path for GetAppConfigDir is returned (https://bugs.freepascal.org/view.php?id=20706 - ignore the function proposed there as it uses the File Manager API which is deprecated in macOS 10.8 and later). Your function will nevertheless work with older versions as well? Minimum supported version currently is 10.4. Quote from: trev on May 28, 2020, 03:26:34 pmFrom osutil.inc: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function DGetAppConfigDir(Global : Boolean) : String; begin  Result:=ExcludeTra ilingPathDelimiter(ExtractFilePath(ParamStr(0)));end;  Where does the Global boolean get actioned? Nowhere. That's why it is the default/fallback implementation. For *nix systems HAS_OSCONFIG is set as well and implemented in rtl/unix/sysutils.pp. Quote from: trev on May 28, 2020, 03:26:34 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i { ---------------------------------------------------------------------    Fallback implementations for AppConfigDir implementation.  --------- ------------------------------------------------------------}{ If a particular OS does it different: - set the HAVE_OSCONFIG define before including sysutils.inc. - implement the functions. Default config assumes a DOS-like configuration.} {$ifndef HAS_OSCONFIG}Function GetAppConfigDir(Global : Boolean) : String; begin  Result:=DGetAppConfigDir(Global);end;  1) Is the HAVE_OSCONFIG in the comment wrong as the code uses HAS_OSCONFIG ? Correct. I have fixed the comment. Quote from: trev on May 28, 2020, 03:26:34 pm2) How to specify darwin? Obviously {$if define(darwin)} would do it, but in the context of using HAS/HAVE_OSCONFIG how does one do it? I couldn't see any examples in the code. I'm guessing that in sysutils.inc: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$if define(darwin)}Function GetAppConfigDir(Global : Boolean) : String;begin  // fill in bodyend; Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String; begin // fill in bodyend; {$define HAS_OSCONFIG}{$endif darwin} { OS utility code }{$i osutil.inc}  Am I close? Not quite. You need to implement your check for DARWIN inside rtl/unix/sysutils.pp as that already provides GetAppConfigFile and GetAppConfigDir itself. Quote from: trev on May 28, 2020, 03:26:34 pm3) What does "Default config assumes a DOS-like configuration." mean? Exactly what you noticed above: there is no difference between global and user configuration. This comment refers to the default implementation of DGetAppConfigDir. Quote from: trev on May 28, 2020, 03:26:34 pmStill in osutil.inc, should not: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  in fact be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function DGetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  That is, the D prefix is missing on the function definition? No. The function GetAppConfigFile with one argument is simply a convenience function for GetAppConfigFile with two arguments as such it is not a default implementation (like DGetAppConfigDir and DGetAppConfigFile), but the final implementation. ---------------------------------------------------------------------- trev · 2020-05-29 00:50 Thanks, that clears up a few puzzlements. Back to osutil.inc, I dislocated the D I was talking about... this is what is there: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  Should it not be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=DGetAppConfigFile(Global,False);  <--------- with Dend;  which is the pattern that the other functions follow? Otherwise you have GetAppConfigFile() calling itself infinitely. ---------------------------------------------------------------------- lucamar · 2020-05-29 02:38 Quote from: trev on May 29, 2020, 02:50:08 amShould it not be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String;begin  Result:=DGetAppConfigFile(Global,False);  <--------- with Dend;which is the pattern that the other functions follow? Otherwise you have GetAppConfigFile() calling itself infinitely. No, it calls other overload, the one that accepts two parameters, which is where all is done. This wouldn't be needed if there was only one function declared as: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetAppConfigFile(Global: Boolean; SubDir: Boolean = False):string; ---------------------------------------------------------------------- PascalDragon · 2020-05-29 07:12 Quote from: trev on May 29, 2020, 02:50:08 amThanks, that clears up a few puzzlements. Back to osutil.inc, I dislocated the D I was talking about... this is what is there: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=GetAppConfigFile(Global,False);end;  Should it not be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function GetAppConfigFile(Global : Boolean) : String; begin  Result:=DGetAppConfigFile(Global,False);  <--------- with Dend;  which is the pattern that the other functions follow? Otherwise you have GetAppConfigFile() calling itself infinitely. I'll simply repeat what I wrote in my previous post: Quote from: PascalDragon on May 28, 2020, 04:54:36 pmNo. The function GetAppConfigFile with one argument is simply a convenience function for GetAppConfigFile with two arguments as such it is not a default implementation (like DGetAppConfigDir and DGetAppConfigFile), but the final implementation. And as lucamar said, that function is not calling itself, because it calls the function with two parameters. ---------------------------------------------------------------------- trev · 2020-05-29 07:59 Thanks to both of you - I finally got it ---------------------------------------------------------------------- trev · 2020-05-29 12:59 Just noticed: Quote from: PascalDragon on May 28, 2020, 04:54:36 pmYour function will nevertheless work with older versions as well? Minimum supported version currently is 10.4. Yes - NSSearchPathForDirectoriesInDomains() from the Foundation framework applies from macOS 10.0+ so works with every version to date and is not already deprecated. Handy, because I don't see any way to #ifdef a macOS version. ---------------------------------------------------------------------- lucamar · 2020-05-29 14:55 Quote from: trev on May 29, 2020, 02:59:19 pmHandy, because I don't see any way to #ifdef a macOS version. I would matter little, if anything at all, since $IFDEF only works at compilation time and it would compile into your binary a call to a possibly incorrect function. What would work is getting the version at run-time and selecting (or setting a pointer to) one or other call accordingly ---------------------------------------------------------------------- trev · 2020-05-30 01:06 You are so right - my usual context of compiling an application/library/daemon/kernel loadable module is substantially different to that of a compiler. I've only ever done the former, so it's a learning process for an old dog seeking new tricks. Thanks for your insights. ---------------------------------------------------------------------- PascalDragon · 2020-05-30 09:18 Quote from: trev on May 30, 2020, 03:06:55 amYou are so right - my usual context of compiling an application/library/daemon/kernel loadable module is substantially different to that of a compiler. I've only ever done the former, so it's a learning process for an old dog seeking new tricks. Thanks for your insights. To be fair, you are not working on the compiler, but the RTL (aka Run Time Library). The only difference is that it comes precompiled instead of you compiling it together with your application. Thus the RTL needs to determine more things at runtime. Just like it determines at runtime whether it can use SSE2 for System.Move for example (for i386). After all you could use the code on an older Pentium that doesn't support SSE yet... Or using newer functionality of Windows 10 while still supporting Windows XP. ---------------------------------------------------------------------- trev · 2020-05-30 13:05 I have the GetAppConfigDir and GetAppConfigFile x2 functions working standalone, but to incorporate them into sysutils.pp I need CocoaAll and MacOSAll in the Uses clause... except it cannot find them if I add them there Any hints? ---------------------------------------------------------------------- PascalDragon · 2020-05-30 17:08 Quote from: trev on May 30, 2020, 03:05:40 pmI have the GetAppConfigDir and GetAppConfigFile x2 functions working standalone, but to incorporate them into sysutils.pp I need CocoaAll and MacOSAll in the Uses clause... except it cannot find them if I add them there Any hints? You can't use the CocoaAll or MacOSAll units inside the SysUtils unit (or anything that's part of the RTL) as the latter is compiled before the packages are compiled. If you can't provide the necessary types, functions, etc. by hand you'll have to use a callback function approach that can be set up in some unit that can access the units.