Menu

Has anyone had a dependency in a Makefile

2021-02-12
2021-02-21
  • Rich Di Iulio

    Rich Di Iulio - 2021-02-12

    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

     
    • Brian Tiffin

      Brian Tiffin - 2021-02-13

      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

      # Makefile
      .RECIPEPREFIX = >
      
      first := tthello.so
      
      tthello.cob:
      > echo 'DISPLAY "Hello, world".' > tthello.cob
      
      tthello.so: tthello.cob
      > 2>/dev/null cobc -m -free -frelax-syn tthello.cob
      
      hello: $(first)
      > cobcrun tthello
      

      Showing

      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
  • Rich Di Iulio

    Rich Di Iulio - 2021-02-14

    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

     
    • Simon Sobisch

      Simon Sobisch - 2021-02-15

      This was what Brian showcased with the following lines:

      first := tthello.so
      tthello.so: tthello.cob
      
      hello: $(first)
      

      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).

       
      • Brian Tiffin

        Brian Tiffin - 2021-02-15

        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 module a and b, all the modules, a, b, main need to ensure there is a support module built first.

        .PHONY: all
        all: support main
                cobc -x main.cob a.so b.so
        
        a.so: support a.cob
                cobc a.cob
        
        b.so: support b.cob
                cobc b.cob
        
        support: support.cob
                cobc -x support.cob
        

        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
  • Rich Di Iulio

    Rich Di Iulio - 2021-02-16

    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

     
    • Brian Tiffin

      Brian Tiffin - 2021-02-16

      :-)

      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 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

       
    • Simon Sobisch

      Simon Sobisch - 2021-02-16

      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?

       
  • Rich Di Iulio

    Rich Di Iulio - 2021-02-19

    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
    • Simon Sobisch

      Simon Sobisch - 2021-02-20

      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.

       
      • Rich Di Iulio

        Rich Di Iulio - 2021-02-21

        Simon,

        Thank you for the note.

        Rich Di Iulio

         

Anonymous
Anonymous

Add attachments
Cancel