My development project is getting larger and I need to use a Makefile to compile the application. I have one program that needs to be compiled before any of the others are. I tried looking through the discussions here and did not find anything. I tried searching the web and was not able to find anything either or was confused.
I would appreciate any help.
Rich Di Iulio
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
prompt$ rm tthello*
prompt$ make hello
echo 'DISPLAY "Hello, world".' > tthello.cob
2>/dev/null cobc -m -free -frelax-syn tthello.cob
cobcrun tthello
Hello, world
prompt$ make hello
cobcrun tthello
Hello, world
The idea is to set a variable with the needed prereq, and include that variable in all target prereq lists.
In this case, tthello.so is the prereq that is required first. Hello mentions it (I'm unclear about order of operations, but I'm assuming left to right means do left before anything further right, and could be wrong under -jNNN parallel make passes. Each and every target would then start with $(first) in the list of prereqs. (any name you'd like, I just picked "first").
If you need more Rich, ask again, it's complicated and this sample is fraught with edge cases that I haven't studied. There may well be a far better idiom. As an example, a small two line shell script placed in your local path, that ensures the prereq and then calls make "${@}" which passes in any args from the script to make.
And this sample looks more complicated that it should, as I wanted to create the tthello.cob in the Makefile itself as the required file that needs to get compiled first. I'm also not a big fan of tabs, and use a different command (recipe) prefix (which means you can cut'n'paste that sample from the forum here and it'll still work, no x'09' characters required in the clipboard manager.
Cheers.
Blue
Last edit: Brian Tiffin 2021-02-13
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your response. .RECIPEPREFIX is for replacing the <tab> with another character. The question still remains. I am looking to building a default/Initial target.</tab>
Rich Di Iulio
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
When running make hello make is instructed to first check if anything in $(first) needs to be updated. As it contains tthello.so this one is checked, which itself has a dependency (this time without a variable) on tthello.cob. As this has no dependency on its own it is only checked for existence (so the rules for it will only be executed once).
That is the dependency order. As Brian showed you can have those both in a variable and/or as plain text (you can also use file extension based rules, for example to compile all .cob in a specific folder to -so/.dll with a single rule).
Additional to a dependency order you can add a "target" to the .PHONY special entry - in this case it will be considered to be always need an update (warning - if you add this to a dependency too then "something" will always be built, even if everything is up-to-date, you commonly would only want to do this in a special force-update target or similar).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is still feeling like it buries some of the goal. make assumes a "default" target (for when you just type make and nothing else), the first one encountered is the default. (Unless told otherwise with a .DEFAULT instruction).
So, most people make an all target, at the top of the Makefile. It's marked as PHONY as there won't be any all file on disk when this is complete. Make needs to know that there won't be any all file to test when it builds up the dependency graph.
Avoiding that complication, the sample uses support as the "must come first" target.
You want to tell all the other targets that they depend on support first.
That's one way of doing it, fairly safe (as long as any new targets don't forget to add support as an initial dependency).
If make decides "hey, I could build a and b in parallel", well they both need supportbuilt first. make will figure this out and ensure support is built before either a or b (or main).
But, this solution is manual, and at risk of aging poorly.
Hope that unfogs some of the necessary details.
Cheers,
Blue
Last edit: Brian Tiffin 2021-02-23
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Brian, I was able to understand the last example. I was then able to get the object to be the first object to be worked on. However, the object was not built (I have attached the log). I have also attached the Makefile.
You are programming make rules well beyond programming in the small here, Rich,
I'd start with make -n -d and see if there are any clues. There can be reams of debug output from make, so prepare to gloss over most and key on the target you expect to always get built first.
See how often that target is mentioned in the debug output, then focus on those little bits of the Directed Acyclic Graph, and play computer tracing back why the target might not have been built. If you get really stuck, then maybe something like Graphviz gvmake, and get some nice pictures to help trace with pen and paper.
Cheers,
Blue
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I assume you want the GUIJAPI_OBJ to be built first...
Are you really sure you the the call FixPath at all? That makes reading the makefile much harder...
GUIJAPI.log shows that everything is fine, so what is the issue?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Okay, Brian, I was finally able to get the Makefile to build my application. I uncomplicated it for use in Linux. Now that I have a working build, I can now try and get a cross-platform version working. I had a typo in the Makefile. It only took me two days. As I said in my other response, your last example did it for me.
Again, thank you both Brian and Simon for your help and suggestions.
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just one note: cross platform is normally quite easy as you can use Unix style slashes for the paths, too.
So it is often only the file ending like EXEEXT and SOEXT, possibly OBJEXT your need to convert to a variable, which you can then set at the top.
If you use system commands like cp or rm and those are not available on the second system then move those to a variable, too.
Hi All,
My development project is getting larger and I need to use a Makefile to compile the application. I have one program that needs to be compiled before any of the others are. I tried looking through the discussions here and did not find anything. I tried searching the web and was not able to find anything either or was confused.
I would appreciate any help.
Rich Di Iulio
As far as I know, you'll have to mention the prerequisite in all the targets that needs the prereq.
For example: excuse, Makefiles resist programming in the small clear examples
Showing
The idea is to set a variable with the needed prereq, and include that variable in all target prereq lists.
In this case, tthello.so is the prereq that is required first. Hello mentions it (I'm unclear about order of operations, but I'm assuming left to right means do left before anything further right, and could be wrong under -jNNN parallel make passes. Each and every target would then start with
$(first)
in the list of prereqs. (any name you'd like, I just picked "first").If you need more Rich, ask again, it's complicated and this sample is fraught with edge cases that I haven't studied. There may well be a far better idiom. As an example, a small two line shell script placed in your local path, that ensures the prereq and then calls
make "${@}"
which passes in any args from the script to make.And this sample looks more complicated that it should, as I wanted to create the tthello.cob in the Makefile itself as the required file that needs to get compiled first. I'm also not a big fan of tabs, and use a different command (recipe) prefix (which means you can cut'n'paste that sample from the forum here and it'll still work, no x'09' characters required in the clipboard manager.
Cheers.
Blue
Last edit: Brian Tiffin 2021-02-13
Brian,
Thank you for your response.
.RECIPEPREFIX
is for replacing the <tab> with another character. The question still remains. I am looking to building a default/Initial target.</tab>Rich Di Iulio
This was what Brian showcased with the following lines:
When running
make hello
make is instructed to first check if anything in$(first)
needs to be updated. As it containstthello.so
this one is checked, which itself has a dependency (this time without a variable) ontthello.cob
. As this has no dependency on its own it is only checked for existence (so the rules for it will only be executed once).That is the dependency order. As Brian showed you can have those both in a variable and/or as plain text (you can also use file extension based rules, for example to compile all .cob in a specific folder to -so/.dll with a single rule).
Additional to a dependency order you can add a "target" to the
.PHONY
special entry - in this case it will be considered to be always need an update (warning - if you add this to a dependency too then "something" will always be built, even if everything is up-to-date, you commonly would only want to do this in a specialforce-update
target or similar).Yeah, sorry Rich, I had the suspicion I was making that example too complicated and burying the actual goal in details. Posted it anyway,
Basically, sans some of the details.
This make shows a
main
program, built from modulea
andb
, all the modules,a
,b
,main
need to ensure there is asupport
module built first.This is still feeling like it buries some of the goal.
make
assumes a "default" target (for when you just typemake
and nothing else), the first one encountered is the default. (Unless told otherwise with a .DEFAULT instruction).So, most people make an
all
target, at the top of the Makefile. It's marked as PHONY as there won't be anyall
file on disk when this is complete. Make needs to know that there won't be anyall
file to test when it builds up the dependency graph.Avoiding that complication, the sample uses
support
as the "must come first" target.You want to tell all the other targets that they depend on
support
first.That's one way of doing it, fairly safe (as long as any new targets don't forget to add
support
as an initial dependency).If make decides "hey, I could build
a
andb
in parallel", well they both needsupport
built first.make
will figure this out and ensuresupport
is built before eithera
orb
(ormain
).But, this solution is manual, and at risk of aging poorly.
Hope that unfogs some of the necessary details.
Cheers,
Blue
Last edit: Brian Tiffin 2021-02-23
Brian/Simon,
Thank you both for responding .
Brian, I was able to understand the last example. I was then able to get the object to be the first object to be worked on. However, the object was not built (I have attached the log). I have also attached the Makefile.
Rich Di Iulio
:-)
Oh, yeah, I remember these...
You are programming make rules well beyond programming in the small here, Rich,
I'd start with
make -n -d
and see if there are any clues. There can be reams of debug output frommake
, so prepare to gloss over most and key on the target you expect to always get built first.See how often that target is mentioned in the debug output, then focus on those little bits of the Directed Acyclic Graph, and play computer tracing back why the target might not have been built. If you get really stuck, then maybe something like Graphviz gvmake, and get some nice pictures to help trace with pen and paper.
Cheers,
Blue
I assume you want the
GUIJAPI_OBJ
to be built first...Are you really sure you the the
call FixPath
at all? That makes reading the makefile much harder...GUIJAPI.log shows that everything is fine, so what is the issue?
Okay, Brian, I was finally able to get the Makefile to build my application. I uncomplicated it for use in Linux. Now that I have a working build, I can now try and get a cross-platform version working. I had a typo in the Makefile. It only took me two days. As I said in my other response, your last example did it for me.
Again, thank you both Brian and Simon for your help and suggestions.
Just one note: cross platform is normally quite easy as you can use Unix style slashes for the paths, too.
So it is often only the file ending like EXEEXT and SOEXT, possibly OBJEXT your need to convert to a variable, which you can then set at the top.
If you use system commands like cp or rm and those are not available on the second system then move those to a variable, too.
Simon,
Thank you for the note.
Rich Di Iulio