0

I'm having some trouble using GNU ar script from a Makefile. Specifically, I'm trying to follow an answer to How can I combine several C/C++ libraries into one?, but ar scripting isn't well supported by make, as most Makefiles use the ar command-line interface and not a script. ar needs each line to be terminated by a new line (\n). This is not the same as multiple shell commands which can use a semicolon as a separator.

The ar commands are:

ar -M <<CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
ranlib libab.a

I'm trying to merge the libraries because I'm creating a static library in a Makefile which depends on another static library, but the second one is created with CMake.

foo.a: foo.o
    $(AR) $(ARFLAGS) $@ $^

final_lib.c: foo.a the_cmake_library.a
    $(AR) -M <<CREATE $@
        ADDLIB foo.a
        ADDLIB the_cmake_library.a
        SAVE
        END
    ranlib $@

The above doesn't work because make is interpreting the ar commands as its own, so I'm getting a

make: CREATE: Command not found

If these were bash commands, I could use something like this answer, but that doesn't work:

ar -M <<CREATE libab.a; ADDLIB liba.a; ADDLIB libb.a; SAVE; END

ar doesn't have a command-line version of the ADDLIB command.

My current solution is:

final_lib.c: foo.a the_cmake_library.a
    $(shell printf "EOM\nCREATE $@\nADDLIB foo.a\nADDLIB the_cmake_library.a\nSAVE\nEND\nEOM\n" > ARCMDS.txt)
    $(AR) -M < ARCMDS.txt
    ranlib $@

I find that very clumsy. Does anyone know of a better way to handle ar scripts in a Makefile? Thanks!

Leonardo
  • 1,533
  • 17
  • 28
  • Why don't use cmake? As for GNU Makefile, use backslashes in the shell script or `$(shell ...)` – 273K Sep 20 '22 at 17:08
  • 1
    I don't really agree that the linked answers are very helpful in this situation. The way I would solve this is change your recipe to: `(echo EOM; echo CREATE $@; echo ADDLIB ...) | $(AR) -M` – MadScientist Sep 20 '22 at 17:17
  • @273, I got into this mess exactly because I'm slowly converting a complex build system to CMake, Not my call to take the plunge and completely switch to CMake (I'd like that very much). – Leonardo Sep 20 '22 at 18:34
  • How would using cmake make this any simpler? It's actually _harder_ to do some things in cmake than in make. It seems like this suggestion is often posted as a knee-jerk reaction to any question about makefiles. Sure, there are situations where cmake is really the best answer. But there are other situations where it's not. How would it be if half the questions about a problem in Python received the answer "why don't you use Rust?" – MadScientist Sep 21 '22 at 14:24
  • If my main project used CMake, I'd just `add_subdirectory(the_cmake_library)`, no? – Leonardo Sep 21 '22 at 17:15

1 Answers1

1

You don't need to use the shell function and you don't need to write it to a file. ar is taking from stdin anyway so why not just use a pipe?

Either:

final_lib.c: foo.a the_cmake_library.a
        printf "EOM\nCREATE $@\nADDLIB foo.a\nADDLIB the_cmake_library.a\nSAVE\nEND\nEOM\n" | $(AR) -M
        ranlib $@

Or something like:

final_lib.c: foo.a the_cmake_library.a
        (echo EOM; \
         echo "CREATE $@"; \
         echo ADDLIB foo.a; \
         echo ADDLIB the_cmake_library.a; \
         echo SAVE; \
         echo END; \
         echo EOM) \
            | $(AR) -M
        ranlib $@
MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Yes, using a pipe to `stdin` is much, much cleaner. I was too far down the rabbit hole to realize that; thanks for the answer! – Leonardo Sep 21 '22 at 17:18