0

I want two Makefile targets which both create the same targetfile but with some bonus files added to the normal files in the bonus rule (all files inside the final .a though). Which in itself is pretty easy, but i want both rules to not relink. By not relinking i mean not executing the ar command if the prereq-files didn't change. So showing that "Nothing to be done for target" in the terminal is what i want.

I thought about changing the OBJ'S var before calling the same $(NAME) target to get that to happen.

SRC = test1.c
BSRC = test2.c

OBJ = $(SRC:.c=.o) 
BOBJ = $(BSRC:.c=.o)
NAME = libtest.a
CC = gcc

all: $(NAME)

bonus: OBJ += $(BOBJ)
bonus: $(NAME)

$(NAME): $(OBJ)
    ar rcs $@ $^

this will result in:

compile_test> make bonus 
gcc    -c -o test1.o test1.c
ar rcs libtest.a test1.o

i am in confusion about why the first line of the bonus rule isn't working. I can add to the CFLAGS or to the SRC's: e.g.

SRC = test1.c
BSRC = test2.c

OBJ = $(SRC:.c=.o) 
BOBJ = $(BSRC:.c=.o)
NAME = libtest.a
CC = gcc
CFLAGS = -Wall

all: $(NAME)

bonus: SRC += $(BSRC)
bonus: OBJ += $(BOBJ)
bonus: CFLAGS += -g
bonus: $(NAME)

$(NAME): $(OBJ)
    ar rcs $@ $^

$(OBJ): $(SRC)
    $(CC) $(SRC) $(CFLAGS) -c

will run like this:

compile_test> make bonus 
gcc test1.c test2.c -Wall -g -c
ar rcs libtest.a test1.o

so it added to the SRC and to the CFLAG but not to the OBJ. At first i thought it would be something with $(OBJ) beeing a prerequisit of the target, but then after this test adding to SCR (a prerequisite as well) that idea got rewoked. I want to know why i cant add to OBJ.

ludmuterol
  • 5
  • 1
  • 5
  • I don't know what "i want both rules to not relink" means. But the reason it doesn't do what you want is described in the manual for target-specific variables: _As with automatic variables, these values are only available within the context of a target’s recipe_. You are using `$(OBJ)` in the prerequisite list, not in the recipe, so your target-specific variables don't have any effect. Why don't you just use `bonus: $(BOBJ)` to add more prerequisites? Why are you trying to use a target-specific variable here? – MadScientist Dec 08 '22 at 16:31
  • because if i just do `bonus: $(BOBJS)` ` ar rcs $(NAME) $^` then this rule will relink. by relink i mean execute the command even if the prerequisites didnt change. – ludmuterol Dec 08 '22 at 16:38
  • and it seems i dont understand what you mean by "to add more prerequisites" and if its a context problem, why has SRC not the same problem? – ludmuterol Dec 08 '22 at 16:45
  • Execute _what_ command? You don't say, and nothing in the makefile actually runs the linker. Adding objects to `bonus` won't cause the library to be rebuilt (the `ar` command). Adding to `SRC` works because you are using `$(SRC)` in the recipe of the rule. – MadScientist Dec 08 '22 at 17:02
  • Yes, sorry i mean the ar Command. Am i not using the $(OBJ) in the recipe? i use it with the $^ inside the ar command, no? – ludmuterol Dec 08 '22 at 17:38
  • No. To use `$(OBJ)` in the recipe means to actually use `$(OBJ)` in the recipe, like you did with `$(SRC)`. You used `$^` which means, expand to whatever the list of prerequisites is. The prerequisites are just `test1.o` so that's all that `$^` expands to. The critical concept to grasp is that make proceeds in two steps: first all the makefiles are parsed and evaluated except for the recipes. Then make runs the commands in the recipes to build the targets; recipes are expanded when make runs the commands. See https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html – MadScientist Dec 08 '22 at 18:01

1 Answers1

0

I think I see; you mean "compiling" where you say "linking" in your question. I will explain what is happening by expanding the variables in your makefile.

So, after expanding this is what make sees for rules:

bonus: SRC += test2.c
bonus: OBJ += test2.o
bonus: CFLAGS += -g
bonus: libtest.a

libtest.a: test1.o                    # 1
        ar rcs libtest.a test1.o      # 2

test1.o: test1.c                      # 3
        gcc test1.c test2.c -Wall -c  # 4

At line #1 we can see that $(OBJS) expanded to test1.o, because as described in the docs the target-specific change only applies to recipes, not prerequisites.

At line #2 we can see that $^ expands to just test1.o because that's the list of prerequisites for this rule.

At line #3 we can see that $(OBJS) expands to test1.o and $(SRC) expands to test1.c for the same reason as above: target-specific variables are in effect only in recipes not in targets or prerequisites.

At line #4 we can see that $(SRCS) expands to both test1.c and test2.c, because finally here we're using a target-specific variable setting inside a recipe. But, this rule is wrong because (a) it builds two output files: test1.o and test2.o, but (b) the target test1.o in the rule tells make that this rule only builds test1.o.

This is the reason make runs the compiler twice if you run make bonus: it tries to build test1.o using your recipe, but it doesn't know that this rule builds two output files so it uses a built-in recipe to also build test2.o.

Before we can tell you what you need to change, you need to tell us what you actually want your makefile to do when you run make bonus because it's really not clear. Do you want it to build the "normal" libtest.a, which contains only test1.o, and then in addition build an extra test2.o which is not in libtest.a? Or do you want libtest.a to contain both objects if you run make bonus?

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thank you for this step by step to explain what the difference between SRC and OBJ is. I think i understand what the "only in recipes" means now. I want the lib.a to contain both files after executing make bonus, so both c files get compiled and both .o files get combined into one .a. – ludmuterol Dec 08 '22 at 19:34
  • and i just figured out that if i add the `$(BOBJ)` to the prerequisites of the `$(NAME)` then both rules work as they should, the only thing to remark is, that if i run make and afterwards make bonus the output says nothing to be done instead of making the lib bigger. I understand why this happens, is there a way to do that as well? it seems like sth in direct conflict with the "not recompiling/repacking into .a" rule... – ludmuterol Dec 08 '22 at 19:47
  • (and i replaced $^ with $(OBJ)) – ludmuterol Dec 08 '22 at 19:53
  • In general it's just a bad idea to have the same output (`libtest.a`) built from different inputs depending on the command line arguments. It leads to nothing but tears since you never know what the _current_ version of the library contains. Did it have the extra objects? Or not? Make looks at the modification times of files (technically, through a special dispensation, it can also look into static libraries, but nothing else). I just recommend you reconsider what you want to do. – MadScientist Dec 08 '22 at 22:23