Home > other >  Using a C macro within a makefile
Using a C macro within a makefile

Time:06-23

I have a shell script that will create a version information header file, version.h, which looks like

echo -e "\
#pragma once\n\
\n\
#include \"build_config.h\"\n\
\n\
\n\
#define COMMIT_REVISION                 \"${GIT_HEAD^^}\"\n\
#define COMMIT_FIRST_FOUR_BYTES         0x$(cut -c 1-8 <<< ${GIT_HEAD^^})\n\
#define CHECKOUT_SHA                    \"${CHECKOUT_SHA}\"\n\
#define CURRENT_SHA                     \"${CURRENT_SHA}\"\n\
#define DATE_OF_SHA                     \"${DATE_OF_SHA}\"\n\
#define BUILD_TYPE                      \"${BUILD_TYPE}\"\n\
\n\
#define BINARY_BASE_NAME               BUILD_TYPE \"_\" DATE_OF_SHA \"_\" CURRENT_SHA\n\" > ${1}

The environment variables used in the script are set during the execution of the script file. For instance, GIT_HEAD="$(git rev-parse HEAD)"

The resulting header file the script creates looks like

#pragma once

#include "build_config.h"


#define COMMIT_REVISION                 "D70B1A73915F11BF5BF3A9D531BF57BA3D58CD73"
#define COMMIT_FIRST_FOUR_BYTES         0xD70B1A73
#define CHECKOUT_SHA                    "d70b1a73"
#define CURRENT_SHA                     "d70b1a7391"
#define DATE_OF_SHA                     "220621"
#define BUILD_TYPE                      "E"

#define BINARY_BASE_NAME               BUILD_TYPE CONTROLLER_CHIP_ID_CHAR CONTROLLER_CHIP_VERSION_CHAR DATE_OF_SHA "_" CURRENT_SHA

Within a makefile is there a way to use the macro BINARY_BASE_NAME within a target recipe? Something like

bin/$(BINARY_BASE_NAME): bin/binary_object.o version.h
  $(V)cp bin/object.o bin/$(BINARY_BASE_NAME)

Would I need to export BINARY_BASE_NAME as an environment variable? Can the makefile use the macro directly?

CodePudding user response:

Not really. Make is not a C compiler, and a header file is not a makefile: make can't parse C code.

You could try to play a trick like, write a C file that included the above file then simply assigned it, and only run that C file through the preprocessor and not the compiler. It would be kind of a hack. Something like this MIGHT work:

# trick to get a variable $S that contains a single space
E :=
S := $E $E

include version.mk
_basename := $(subst ",,$(subst $S,,$(_basename)))

version.mk : version.h
        (echo '#include "$<"'; echo '_basename := BINARY_BASE_NAME') > [email protected]
        $(CC) $(CFLAGS) -E [email protected] > $@

it might work.

ETA

Just to promote my comment below: the best way to do this is to either write another shell script that generates the makefile info like version.mk, or else enhance the shell script that creates version.h so that it also writes the same information to a file version.mk. That would be a lot safer and more reliable.

CodePudding user response:

Pushing MadScientist's approach one step further you could generate a real piece of C code that prints this macro, compile it, execute it and redirect the output to the included Makefile. Simplified demo:

The simplified version.h:

#define CURRENT_SHA         "d70b1a7391"
#define DATE_OF_SHA         "220621"
#define BUILD_TYPE          "E"

#define BINARY_BASE_NAME    BUILD_TYPE DATE_OF_SHA "_" CURRENT_SHA

The Makefile file:

include version.mk

define C_code
#include <stdio.h>
#include "$<"

int main(void) {
  printf("BINARY_BASE_NAME := %s\n", BINARY_BASE_NAME);
  return 0;
}

endef
export C_code

version.mk : version.h
    printf '%s\n' "$$C_code" > "[email protected]"
    $(CC) $(CFLAGS) -o "[email protected]" "[email protected]"
    "./[email protected]" > "$@"

.PHONY: all clean

all:
    @printf '%s\n' "$(BINARY_BASE_NAME)"

clean:
    rm -f version.mk.c version.mk.exe version.mk

And then:

$ make all
printf '%s\n' "$C_code" > "version.mk.c"
cc  -o "version.mk.exe" "version.mk.c"
"./version.mk.exe" > "version.mk"
E220621_d70b1a7391

$ cat version.mk.c
#include <stdio.h>
#include "version.h"

int main(void) {
  printf("BINARY_BASE_NAME := %s\n", BINARY_BASE_NAME);
  return 0;
}

$ cat version.mk
BINARY_BASE_NAME := E220621_d70b1a7391

$ make clean
rm -f version.mk.c version.mk.exe version.mk

CodePudding user response:

If your shell script creates a header, why not make it also create a Makefile snippet that gets included by your main Makefile?

echo "BINARY_BASE_NAME := ${BUILD_TYPE}_${DATE_OF_SHA}_${CURRENT_SHA}" > makefile.inc

Then use a GNU make include makefile.inc directive.

  • Related