Recent

Author Topic: Mac application bundle and ExtractFilePath(Application.ExeName)  (Read 8393 times)

FangQ

  • Full Member
  • ***
  • Posts: 134
In a portable program, I use ExtractFilePath(Application.ExeName) to find the folder containing the executable path, and then write output in a subfolder.
This works well for Linux and Windows, but failed on my Mac. The program is launched using the application bundle (progname.app). It turns out the ExtractFilePath(Application.ExeName) extract a temporary path that is super long.

I am wondering if there is a workaround for scenarios like this, how can I find the path of the application where the progname.app is located?

thanks

mischi

  • Full Member
  • ***
  • Posts: 170
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #1 on: March 22, 2018, 10:42:28 pm »
How about using Apple's API within an ifdef darwin?

FangQ

  • Full Member
  • ***
  • Posts: 134
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #2 on: March 22, 2018, 10:52:06 pm »
@mischi, I am not sure which specific Apple API you were referring to. any examples? thanks

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #3 on: March 23, 2018, 12:02:29 am »
In a portable program, I use ExtractFilePath(Application.ExeName) to find the folder containing the executable path, and then write output in a subfolder.

Your app should not store things in the app bundle. Bad idea. Period.

You should create the folder in one of the locations that macOS provides, typically under ~/Library/Application Support. Create your folder there using your app's bundle ID as the folder name.

https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html

You may be doing other things that non-Mac developers often try to drag in from the Windows or Linux worlds. A good way to root out these bad practices is just to go through the exercise of sandboxing your app. You may be surprised at how ill-disciplined your app is. But don't worry, in many cases these problems are easy to fix once you're spent a few minutes reading Apple's docs and learning about programming best practices on macOS. Here's a Pascal-oriented article on sandboxing that will help you get started:

https://macpgmr.github.io/

FangQ

  • Full Member
  • ***
  • Posts: 134
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #4 on: March 23, 2018, 04:31:41 am »
Your app should not store things in the app bundle. Bad idea. Period.

in fact, I don't, and not intend to, store anything inside the app bundle folder. as I mentioned, I want my program to be portable (such as ready-to-run on an USB drive), meaning that people unzip, and run without needing installation. I want to store the output of the program "along side" with the app, something like

Code: Pascal  [Select][+][-]
  1. AppUnzipFolder/
  2.   |-- myapp   (binary)
  3.   |-- myapp.app/
  4.   |       |-Contents
  5.   |               |-MacOS
  6.   |               |- ...
  7.   |-- Output
  8.          |- output1


as you see, I do not put my output file inside myapp.app, but I just want to find out the folder containing the app, and create an Output folder.

You should create the folder in one of the locations that macOS provides, typically under ~/Library/Application Support. Create your folder there using your app's bundle ID as the folder name.

https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html

I did some search earlier, and found that GetUserDir or GetAppConfigDir may be an alternative, but still, making my software portable and self-contained is a feature I would love to keep.

You may be doing other things that non-Mac developers often try to drag in from the Windows or Linux worlds. A good way to root out these bad practices is just to go through the exercise of sandboxing your app. You may be surprised at how ill-disciplined your app is. But don't worry, in many cases these problems are easy to fix once you're spent a few minutes reading Apple's docs and learning about programming best practices on macOS. Here's a Pascal-oriented article on sandboxing that will help you get started:

https://macpgmr.github.io/

again, I still don't think having an installation-free and portable package design (such as USB storage based) is an "ill-disciplined" idea. I consider it as a feature, and if there are mechanisms that I can use in lazarus to keep this feature, I will be happy.

mischi

  • Full Member
  • ***
  • Posts: 170
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #5 on: March 23, 2018, 11:24:31 am »
The first step is to move the binary into the bundle. i.e. into the directory Contents/macOS. Lazarus does not handle this correctly.

Here is the link to Apple's Filesystem API: https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide

Trenatos

  • Hero Member
  • *****
  • Posts: 533
    • MarcusFernstrom.com
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #6 on: April 10, 2018, 05:23:44 pm »
I've tried figuring out how to get Lazarus to move it into the proper bundle directory when building, but have not succeeded.   :/

As for paths, I usually use ifdef darwin / linux / windows depending on what I need, such as paths being slightly different, that way cross compile works fine.

I store files in the bundle and it works just fine, afaik a bundle is just a directory handled specially by OSX/MacOS.

I also store files using the get config functions, search the word "config" on this page and you'll see what I mean:  https://www.freepascal.org/docs-html/rtl/sysutils/index-5.html

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #7 on: April 10, 2018, 05:29:18 pm »
I've tried figuring out how to get Lazarus to move it into the proper bundle directory when building, but have not succeeded.   :/

Right, Lazarus can't do that - a defect by design, I guess.

If you create a new project with LazXProj's File | New item, it will automatically run a little console app after compiling that updates the app bundle properly.

https://macpgmr.github.io/MacXPlatform/LazXProj.html


mischi

  • Full Member
  • ***
  • Posts: 170
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #8 on: April 10, 2018, 05:39:57 pm »
I store files in the bundle and it works just fine, afaik a bundle is just a directory handled specially by OSX/MacOS.
correct.
I also store files using the get config functions, search the word "config" on this page and you'll see what I mean:  https://www.freepascal.org/docs-html/rtl/sysutils/index-5.html
I am not really sure, but i do not think that these return paths, which are in conformance with apple guide lines. Briefly, user specific preference files should be ~/Library/Preferences, system wide ones in /Library/Preferences. Resource files, which are not changed by the user, but might be changed from one version to another should go in the Resources folder in the bundle. Files, which might changed and should be kept as they are with the next version should go into ~/Library/Application Support/YourProgram/ or /Library/Application Support/YourProgram/. Log files into  ~/Library/Logs and /Library/Logs.

I used a now outdated API for preferences some time ago: https://sourceforge.net/p/heatwizard/code-0/HEAD/tree/trunk/UPreferenceData.pas

MiSchi

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #9 on: April 10, 2018, 05:43:41 pm »
I am not really sure, but i do not think that these return paths, which are in conformance with apple guide lines. Briefly, user specific preference files should be ~/Library/Preferences, system wide ones in /Library/Preferences. Resource files, which are not changed by the user, but might be changed from one version to another should go in the Resources folder in the bundle. Files, which might changed and should be kept as they are with the next version should go into ~/Library/Application Support/YourProgram/ or /Library/Application Support/YourProgram/. Log files into  ~/Library/Logs and /Library/Logs.

Correct.

The config functions are for a generic Unix system. macOS is not a generic Unix system and should not be treated like one. It's like treating humans as chordates instead of as humans.
 

Trenatos

  • Hero Member
  • *****
  • Posts: 533
    • MarcusFernstrom.com
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #10 on: April 10, 2018, 05:48:15 pm »
Write once, compile maybe, and please don't trust functions to return proper cross platform data just because they compile  :)

I like FreePascal but man some stuff drives me bonkers.

Just for the record, this page https://www.freepascal.org/docs-html/rtl/sysutils/getappconfigfile.html doesn't mention anything about being Unix-targeted, in fact they only mention the word Windows, not Linux, Unix, Mac, OSX, etc.
« Last Edit: April 10, 2018, 05:49:46 pm by Trenatos »

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #11 on: April 10, 2018, 05:52:47 pm »
Write once, compile maybe, and please don't trust functions to return proper cross platform data just because they compile  :)

I like FreePascal but man some stuff drives me bonkers.

LazXProj's units take care of a lot of these things for you in a cross-platform way - app config settings (preferences), version info, etc.

The point is to allow non-Mac developers to create proper Mac apps without sweating the details, while also being useful on Windows and Linux.

mischi

  • Full Member
  • ***
  • Posts: 170
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #12 on: April 10, 2018, 08:10:49 pm »
macOS is not a generic Unix system and should not be treated like one. It's like treating humans as chordates instead of as humans.
I had to lookup chordates. Gave me a big smile and made my day.

jwdietrich

  • Hero Member
  • *****
  • Posts: 1232
    • formatio reticularis
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #13 on: April 10, 2018, 09:20:42 pm »

Right, Lazarus can't do that - a defect by design, I guess.

I thought that this defect by design is intended because a binary outside the bundle is more easy to maintain.

On the other hand, your console app demonstrates that other ways are possible (and sensible).
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.2.6 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Mac application bundle and ExtractFilePath(Application.ExeName)
« Reply #14 on: April 10, 2018, 09:32:14 pm »
I thought that this defect by design is intended because a binary outside the bundle is more easy to maintain.

I have no knowledge of the design decision. No other IDE on Mac does it that way.

 

TinyPortal © 2005-2018