Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

SecuritySteve

macrumors 6502a
Original poster
Jul 6, 2017
946
1,071
California
I have an Application that is based on the following sources:

1) A GUI based in Obj-C that does some lightweight processing and graphical display work.
2) A series of sub-programs written in Fortran, that are accessed via NSTask. These programs are legacy code and handle the bulk of scientific calculation for my app.

My current structure is this:

1) .App file lives in Applications folder.
2) Fortran binaries and their resource files live in a series of folders in Application Support.

My problem:

Managing binary signing and resources is a pain outside of Xcode, especially since each binary is currently being compiled and stored separately, and manually. Further, with the move to Apple Silicon I need to develop my Fortran applications away from Intel Fortran (which was shoddy to begin with, and got worse over time), relying instead on GNU Fortran which has an ARM version.

My solution:

I want to rearchitect this application to be more modern from the get-go. I want my Fortran binaries nested in my .App bundle, each with their own folder and capable of generating new sub folders and files. This keeps things nice and sandboxed, with the only external files being accessed now only being the user's save files and such.

I'm already working on recompiling all of the Fortran binaries, but I have run into a snag in Xcode. Since I am adding these fortran binaries in Xcode, I am adding a custom build phase for Fortran source files using gfortran in a build script. However after I add a command line type target (which to my understanding is an additional executable that the project must compile) the project seems to skip over it when I build. I can run my script directly from the main target by adding the source file to that project, but then the files go into some weird intermediate file directory and not the bundle itself. I suspect that this is as simple as just pointing the "output files" list to the bundle, but there doesn't seem to be any script variables for the bundle.

My question:

Am I doing this right? Should I make a target for each individual Fortran binary, or use the main target? Also how do I get the output binaries into the App's Resource folder?
 

Senor Cuete

macrumors 6502
Nov 9, 2011
425
31
Your post raises a lot of questions. You should be able to include your binaries in the app bundle, but you might need to build them as libraries. You shouldn't plan to have the Fortran binaries create new sub-folders and files. This violates the generally accepted principle of not writing self-modifying code and it might not work in an app bundle. The correct place for an app's data is probably in a ~/username/Library/data/...appname/. An example of this is an app's preferences.

The fact that so much important code is still in Fortran is an issue. I had to write a program with complex mathematical calculations that I could only find in Fortran. I wound up going to the algorithms and rewriting them in C. This was a lot of work. There are Fortran to C converters but I haven't used them. They might work.
 

SecuritySteve

macrumors 6502a
Original poster
Jul 6, 2017
946
1,071
California
Your post raises a lot of questions. You should be able to include your binaries in the app bundle, but you might need to build them as libraries. You shouldn't plan to have the Fortran binaries create new sub-folders and files. This violates the generally accepted principle of not writing self-modifying code and it might not work in an app bundle. The correct place for an app's data is probably in a ~/username/Library/data/...appname/. An example of this is an app's preferences.

The fact that so much important code is still in Fortran is an issue. I had to write a program with complex mathematical calculations that I could only find in Fortran. I wound up going to the algorithms and rewriting them in C. This was a lot of work. There are Fortran to C converters but I haven't used them. They might work.
Using them as libraries is a non-option. These need to be standalone executables because they were written in such a way that memory management and variable value saving results in invalid results after the first execution. The files that the fortran binaries are writing are just text files for the most part, so I don't think it really counts as self-modifying code. Back in the day memory was so expensive that it was cheaper to save variable information on scratch files, and that is what these Fortran programs are doing.

These are massive Fortran programs from the 1960s-80s. Rewriting them is a non-option. There's also the issue that the scientists using these applications need to do equation audits if something goes wrong, and it is much easier to read equations in Fortran than it is in C or any other modern language when nested exponential equations are involved. If any of these equations are improperly translated, we have dead astronauts.

To my knowledge, the files will all be deleted after use. This should return the application to a pristine state between operations.

Edit:

But back to the original question, I know in theory I can have this work. My biggest question is how to get each target built and compiled in the Xcode Project and moved appropriately. Right now when I build it skips over the secondary targets in the project.
 

SecuritySteve

macrumors 6502a
Original poster
Jul 6, 2017
946
1,071
California
Update: I found the parallel target build settings under the project scheme settings. Now we just need to see if the run times will work. I will update again when I have some time to update / test.
 

Senor Cuete

macrumors 6502
Nov 9, 2011
425
31
...they were written in such a way that memory management and variable value saving results in invalid results after the first execution. The files that the Fortran binaries are writing are just text files for the most part, so I don't think it really counts as self-modifying code. Back in the day memory was so expensive that it was cheaper to save variable information on scratch files, and that is what these Fortran programs are doing.
Today you would think of this as bad programming. Fortran programmers are an endangered species. Still, one would wonder if a big institution like the one that you work for couldn't find someone who could modernize the code a little to make it easier to reuse. The equations are probably not much more difficult to check in C, it's just a matter of what you are used to reading. Modern debuggers like the one in XCode make it much easier to check what is going on. Can you do this with the Fortran code or are you trusting the binaries?

Tell us how this works out.
 

SecuritySteve

macrumors 6502a
Original poster
Jul 6, 2017
946
1,071
California
Today you would think of this as bad programming. Fortran programmers are an endangered species. Still, one would wonder if a big institution like the one that you work for couldn't find someone who could modernize the code a little to make it easier to reuse. The equations are probably not much more difficult to check in C, it's just a matter of what you are used to reading. Modern debuggers like the one in XCode make it much easier to check what is going on. Can you do this with the Fortran code or are you trusting the binaries?

Tell us how this works out.
Actually the company I'm writing this App for is smaller than you'd think, I am the only developer amidst a bunch of rocket scientists, chemists, etc. And yet their thrusters will be on manned spacecraft. (One of the most professionally fulfilling things is to know that I'm helping that frontier expand)

The biggest example of equation auditing is when you have five levels of nested exponents. The pow(x,y) function being nested five times is hard to read, but a x^(y) is natural. It strikes me as odd that language developers used a function for what used to be an operator. I'd like to know the background on that specific choice. But I digress.

I used to be able to debug in Xcode for Fortran. But I was using Intel Fortran's compiler, which was horribly supported and usually prevented me from upgrading my OS. As stated in the OP, recently I was able to get GNU Fortran working, and now I'm terminal based for the most part on Fortran coding.

But yeah, you'll get no argument from me that by modern standards these Fortran programmers are doing a lot wrong. But it's hard to be able to code for computers 60 years into the future.
 

SecuritySteve

macrumors 6502a
Original poster
Jul 6, 2017
946
1,071
California
So as an update, it looks like things are working! My process to get it working (should anyone else want to compile fortran in Xcode using gfortran) is to add a script build phase for a second target.


Bash:
echo Starting build script with command: gfortran "$SCRIPT_INPUT_FILE_0" -std=legacy -fno-automatic -fmax-subrecord-length=8 -o "$SCRIPT_OUTPUT_FILE_0"
gfortran "$SCRIPT_INPUT_FILE_0" -std=legacy -fno-automatic -fmax-subrecord-length=8 -o "$SCRIPT_OUTPUT_FILE_0"
codesign -f -s "YOUR CERT NAME HERE" "$SCRIPT_OUTPUT_FILE_0"

Then add the input file from your project. For example:

Code:
$(SRCROOT)/PROJECT/Fortran Files/$(PRODUCT_NAME).FOR

And with output file:

Code:
${BUILT_PRODUCTS_DIR}/$(PRODUCT_NAME)

After adding this, go into your main .App target, and add a "Copy Bundle Resources" for your second target itself.

Next, make sure that you go to Product -> Scheme in Xcode's menu bar, and add the second target to your build scheme with the first .App target as a dependency.

Then to launch your sub process...


Objective-C:
NSString *bundlePath = [NSBundle pathForResource:@"FORTRAN_BINARY_NAME_HERE" ofType:nil inDirectory:[[NSBundle mainBundle] resourcePath]];
[myTask setCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];
[myTask setLaunchPath:bundlePath];
@try{
    [myTask launch];

}
@catch(NSException *exception){
    NSLog(@"Failed to launch");
    NSLog(@"%@",exception);
}

There are no runtime problems for adding files to the resources folder, but you will need to clean them up after the sub process runs - including directories. Otherwise the CodeResources file will have incorrect hash information.
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.