简体   繁体   中英

Using a C macro within a makefile

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?

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') > $@.c
        $(CC) $(CFLAGS) -E $@.c > $@

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.

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" > "$@.c"
    $(CC) $(CFLAGS) -o "$@.exe" "$@.c"
    "./$@.exe" > "$@"

.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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM