Shell Error

I’m trying to get the path to an installed binary on my Mac. The binary is called dcmdump. If I type which dcmdump in the Terminal, it correctly lists its installed location as /usr/local/bin/dcmdump. If I try to execute the same command (‘which dcmdump’) with a shell I get no result and an ErrorCode of 1. I even tried using the interactive Shell example provided by Xojo but that doesn’t seem to work either. In that example, the output of the Shell is simply sh-3.s$ (i.e. an empty line).

Am I doing something obviously daft here?

Without looking into this, I can already tell you, you cannot sandbox your app if you are reading /usr/local/bin/…

Not looking to sandbox the app. It won’t be distributed on the App store

If I try to get the path of system binaries, e.g. which ls or which cd then the correct paths (/bin/ls and /bin/cd respectively) are returned…

Where is ‘which’?
I think you need the full path to it in the shell.
Something like ‘/bin/which dcmdump’

I don’t know if ‘which’ is in bin though that is just an example :slight_smile:

For the Shell class you should use the full path of the app.

When I run which which in the Terminal it tells me its path is /usr/bin/which. If I type /usr/bin/which dcmdump in the Terminal it outputs /usr/local/bin but if I type the same command in the Xojo Shell it agains outputs an empty line. This is weird…

You could fake this by using an AppleScript that executes a shellscript.

I guess but that won’t fly with Windows (hoping to get this app running on both OS X and Windows - the dcm toolkit is cross platform).

My other alternative is to include the binaries in the app’s bundle as a framework. That could bypass the sandboxing issue. Trouble is, I get a bit confused when it comes to compiling these tools from source, statically or dynamically linking them to dependencies, etc. Far better to get the user to install the binaries with Homebrew (or Windows equivalent) and then call them from a Shell. At least, that’s what I thought…

I guess the executable isn’t in your path.
Run this command in a Xojo shell:

/bin/cat /etc/paths

If I’m not mistaken your executable needs to be in one of the returned paths to be found with ‘which’.

@Albin Kiland I think you’re right. Looks like I can execute dcmdump if I cd to its directory in the Shell first. Hmmm, might have to re-evaluate how I call this binary.

Can I include the required binaries (and any libraries they require) into the frameworks folder of my app bundle and execute them from there? If I can find the appropriately statically linked binaries and their dependencies and include them in my app bundle would that work? I guess it avoids the end user having to install them but would increase my app size by a moderate amount.

I get the same /usr/bin/which in both terminal and the Interactive Shell example here.

Same result for a synchronous shell.

@Gary: what is the license of the files? Application size for desktop doesn’t really matter nowadays.

@Garry Pettet

You’re right, copying the binary/helper into your bundle is a lot easier.

For OS X:

First run: otool -L dcmdump and see if there are any libs other than standard OS X libraries.

If there aren’t, great because dcmdump is statically compiled and it doesn’t need any dependencies.

If there are, (often) no problem but you need to get those libraries as well. Copy the binary and the needed lib(s) to some subdirectory of your Xojo project. (It gets a bit tricky if those libraries use other libraries as well but you can also check that with otool -L.)
If those libraries (listed with otool -L) are NOT pointing to @executable_path/some.lib, you need to change that with:
install_name_tool -change /old/path/blah/some.lib @executable_path/some.lib dcmdump (<-- from top of my head).
Now some.lib can be used from the same directory as where the binary is called from.

To include them in your bundle: In Xojo, Go to Build->OSX. Then Insert->Build Step-> Copy Files. Then hit the + and select the dcmdump and lib(s) from the subdirectory of your project.
On the right side, make sure it says Subdirectory: /Helpers and Destination: Contents Folder

Now every time you run or build your App, dcmdump and libs are copied into the bundle.

This should help getting to your helper the proper way via a FolderItem:

  Dim ResourcesFolder, Helper As Folderitem
  If ResourcesFolder = Nil or ResourcesFolder.exists = False Then
    Declare Function NSClassFromString Lib "AppKit"(className As CFStringRef) As Ptr
    Declare Function mainBundle Lib "AppKit" selector "mainBundle"(NSBundleClass As Ptr) As Ptr
    Declare Function resourcePath Lib "AppKit" selector "resourcePath"(NSBundleRef As Ptr) As CFStringRef
    ResourcesFolder = getFolderItem(resourcePath(mainBundle(NSClassFromString("NSBundle"))), folderItem.pathTypeNative)
  End If
  Helper = ResourcesFolder.Parent.Child("Helpers").Child(dcmdump)