Makefile instructions to create directories (CentOS7 , GNU Make 3.82)

Hello,

My makefiles are set up to generate an environment specific build directory based on the local configuration and some values passed to make. It generally looks like,

# compilers, may be passed to make
CC++ = g++
FCOMP = gfortran

# version of program, may be passed to make
ver = debug

# manually assign linux distro
OS=CentOS-7.7

# collect name information
ARCH := $(shell uname -m)
KERN := $(shell uname -r | cut -d. -f 1,2)

# find g++ compiler version
# this can vary with the distribution
CMP := $(shell g++ --version | cut -d ' ' -f 3 | sed q)

# create names for build directory name
CNAME := gpp-$(CMP)
FNAME := gfortran-$(CMP)

# archdir is executed as part of all and will create the necessary
# version specific directories if they do not exist
archdir: ${BDIR}

# concatenate the name for the build directory
BDIR := bld_$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directories do not exist
${BDIR}:
    @mkdir -p ${BDIR}

# archdir is part of all
all archdir program_name

When make is called with all, all runs archdir, archdir runs BDIR and the build directory gets created if it does not exist. This has generally worked well.

Recently I wanted to create some additional directories and so attempted to implement the same method.

I added a new directory name and instruction to make the directory. That instruction was added to archdir so that the resulting code looks like,

# archdir is executed as part of all and will create the necessary
# version specific directories if they do not exist
archdir: ${BDIR}  ${TESTDIR}

# create name for the build directory
BDIR := bld_$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directories do not exist
${BDIR}:
    @mkdir -p ${BDIR}

# create name for test directory
TESTDIR = ./test/(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directory does not exist
${TESTDIR}:
    @mkdir -p ${TESTDIR}

The directory ./test/ already exists. When I run the make file with all, the build completes without error but the new directory $TESTDIR is not created.

Any suggestions as to what I am missing here? Do I have a syntax issue? Is something out of order?

Some of this could probably be better done with a config script since there is no way that I know of to collect all of the above from every version of linux and windows with the same code. Sometimes I think it just makes more sense to pass values in the call to make or hard code the make file. Making up a directory name and creating the directory is something I think I should be able to do.

LMHmedchem

Hi,
You have bad declare TESTDIR variable ( Forgot '$' for '(OS)' ) :

TESTDIR = ./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
2 Likes

Thanks for the suggestion, I did fix this error but it did not resolve the issue.

I decided to move the assignment of archdir to after the definitions of ${BDIR} and ${TESTDIR} .

Now the revised code looks like this,

# create name for the build directory
BDIR := bld_$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directories do not exist
${BDIR}:
    @mkdir -p ${BDIR}

# create name for test directory
TESTDIR = ./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directory does not exist
${TESTDIR}:
    @mkdir -p ${TESTDIR}

# archdir is executed as part of all and will create the necessary
# version specific directories if they do not exist
archdir: ${BDIR} ${TESTDIR}

This now works and the test directory is created.

Of course, it seems logical that these instructions should need to be defined in the order above in that a variable is declared and assigned before the value is used. Make has never seemed to function like this. For instance, I have OBJSC = $(OBJCM) $(OBJSCLS) $(OBJSBGR) where OBJSC is a list of objects used in a build rule. The items in the lists, $(OBJCM) , $(OBJSCLS) , etc, are all assigned much later in the makefile after the assignment above. This has no effect and the applications builds correctly. The build rules for the linker always seem to come before the compile rules, which is also counterintuitive.

Perhaps all of my makefiles are set up in the wrong order even though the seem to work in the main?

LMHmedchem

1 Like

Another error that maybe explain why not work when to declare archdir before TESTDIR :

TESTDIR := ./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)

So I wasn't expanding the components variables of TESTDIR correctly? I guess I should have at least noticed the TESTDIR was not being assigned using the same operator as BDIR .

I have tried now to use a similar method to copy files into the newly created directories and am having more issues. It seems to me as if the following code,

# create name for test directory
TESTDIR = ./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)
# mkdir if the directory does not exist
${TESTDIR}:
    @mkdir -p ${TESTDIR}

overwrites the original value of TESTDIR which is,

./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)

with the mkdir instruction such that if you printed ${TESTDIR} after the
second assignment, it would print,

mkdir -p ./test/$(OS)_$(KERN).$(ARCH)_$(CNAME)_$(FNAME)_$(ver)

with the variables such as $(OS) expanded. This would mean that you could no longer use $(TESTDIR) to refer to the location that was originally assigned.

Is this true or am I not understanding how this is working?

LMHmedchem