File structure:
cpp
| Makefile
|
| obj
|___include
| | a.cuh
| | b.cuh
| | c.cuh
|
|___src
| | a.cu
| | b.cu
| | c.cu
I don't have much experience with GNU make. The following was written based on different search results on Stackoverflow. The $# variable correctly gets the name of each object file from the list, however $< variable only gets the first item in the list of source file names (as per the manual, but that is what all the stack overflow answers I found are using 1, 2, 3).
NVCC=nvcc
LIB = lib.dll
SRC_DIR = src
INC_DIR = include
OBJ_DIR = obj
CU_FILES = $(wildcard $(SRC_DIR)/*.cu)
CUH_FILES = $(wildcard $(INC_DIR)/*.cuh)
CUO_FILES = $(addprefix $(OBJ_DIR)/,$(notdir $(CU_FILES:.cu=.obj)))
$(LIB): $(CUO_FILES)
$(NVCC) --shared $^ -o $#
$(CUO_FILES): $(CU_FILES) $(CUH_FILES)
$(NVCC) -dc $< -o $#
What you wrote is probably not what you want. Your rule:
$(CUO_FILES): $(CU_FILES) $(CUH_FILES)
$(NVCC) -dc $< -o $#
means that each object file depends on all source files ad all header files.
What you need here is a pattern rule saying that obj/foo.obj depends on src/foo.cu and include/foo.cuh:
obj/%.obj: src/%.cu include/%.cuh
$(NVCC) -dc $< -o $#
Note that you can simplify a bit the CUO_FILES assignment:
CUO_FILES = $(patsubst $(SRC_DIR)/%.cu,$(OBJ_DIR)/%.obj,$(CU_FILES))
Related
I have been working with a project that only compiles C sources but I've found I need some assembler too, I'm reticent to inline the asm code in a C file as GCC may not interpret it correctly.
My predecesor created the makefile for the project (apologies, it's fairly long):
# Compiler and options
CC := sparc-rtems-gcc
# The application software binary
TARGET := icu_asw
# Source and build directories
SRCDIR := src
BUILDDIR := obj
TARGETDIR := bin
HDSWROOT := ../../hdsw
BSWTOOLS := ../../bsw/sw/tools
SRCEXT := c
DEPEXT := d
OBJEXT := o
MRAMEXT := img.elf
# Flags, libraries and includes
CFLAGS := -std=gnu99 -Wall -Wextra -g
LIBDRV := $(HDSWROOT)/lib/libdrv.a
INCFLAGS := -I$(HDSWROOT)/include -I$(HDSWROOT)/osal/rtems
# Debug flags
DEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=1 -DLOGDEBUG=1 -DLOGINFO=1 -DMAKECHECKS=1
NODEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=0 -DLOGDEBUG=0 -DLOGINFO=0 -DMAKECHECKS=1
#-----------------------------------------------------------------------
# Build instructions
#-----------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
# Default make
all: $(TARGET)
# Remake
remake: cleaner all
# Clean only objects
clean:
#$(RM) -rf $(BUILDDIR)
# Full clean (objects and binaries)
cleaner: clean
#$(RM) -rf $(TARGETDIR)
# Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
# Link (uses an order-only prerequisite for the directories so that they
# don't affect the use of the $^)
$(TARGET): $(OBJECTS) | directories
$(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIBDRV)
# Make the build and target directories
directories:
#mkdir -p $(TARGETDIR)
#mkdir -p $(BUILDDIR)
# Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(INCFLAGS) $(NODEBUGFLAGS) -c -o $# $<
#$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
#cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
#sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
#sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
#rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
# Non-File Targets
.PHONY: all remake clean cleaner
I want to also bring in and compile two .S files, so, I edited the following line
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT) -or -name *.$(ASMEXT))
To bring in the .S files, then I edited the OBJECTS to also include the ASM sources ("*.S")
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)),$(SOURCES:.$(ASMEXT)=.$(OBJEXT)))
But when recompiling with 'make all' I'm getting:
$ make all
make: *** No rule to make target `obj/asi_access.S', needed by `icu_asw'. Stop.
I don't suppose someone could spot where I am going wrong? I think I have not correctly added to the OBJECTS line!
Thanks
The expression $(var:.ext1=.ext2) does not filter by .ext1, i.e.
$(SOURCES:.$(SRCEXT)=.$(OBJEXT)) $(SOURCES:.$(ASMEXT)=.$(OBJEXT))
gives for a test source list the following result
a.o b.o c.S a.c b.c c.o
I.e. you duplicated your files and you have source files in the OBJECTS definition.
The following would be a correct approach:
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%, \
$(patsubst %.$(SRCEXT),%.$(OBJEXT), \
$(patsubst %.$(ASMEXT),%.$(OBJEXT),$(SOURCES)) \
) \
)
UPDATE: you should consider to use 2 separate object lists, so that you can apply different rules for them, e.g.
SOURCES_C := $(filter %.$(SRCEXT),$(SOURCES))
OBJECTS_C := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_C:%.$(SRCEXT)=%.$(OBJEXT)))
SOURCES_ASM := $(filter %.$(ASMEXT),$(SOURCES))
OBJECTS_ASM := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_ASM:%.$(ASMEXT)=%.$(OBJEXT)))
$(OBJECTS_C): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
.... C compiler recipe ....
$(OBJECTS_ASM): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(ASMEXT)
.... assembler recipe ....
$(TARGET): $(OBJECTS_C) $(OBJECTS_ASM) | directories
I have a Fortran code that can be compiled by the following Makefile:
FC = mpif90
FFLAGS := ...
TARGET = run1
SRC = main.f90 param.f90 ...
OBJ = $(SRC:.f90=.o)
all: $(TARGET)
$(TARGET): $(OBJ) $(FC) $(FFLAGS)
...
In the above, the TARGET can be run1 or run2 or run3, depending on the value of a variable in my script. For example, if I have the following in param.f90:
character(len=1), parameter :: case_num = "1"
Then, I want the TARGET variable to be set as run1. Now, the question is how to do that automatically without manually changing the Makefile every time?
I have tried something like
num = $(grep 'case_num = "' param.f90 | sed -n -e 's/^.*case_num = "//p' | cut -c1-1)
TARGET = run$num
in the Makefile, which doesn't work. I have checked that the grep and sed sentence is correct in a regular bash script. How to do this in a Fortran Makefile? Any help is appreciated.
Your makefile appears to a GNU Make makefile. To assign the output of a
shell command to a make variable, you need to use the $(shell ...) function,
like:
num := $(shell grep 'case_num = "' param.f90 | sed -n -e 's/^.*case_num = "//p' | cut -c1-1)
TARGET := run$(num)
SRC_DIRS += $(CMM_DIR)
SRC_DIRS += $(ABC_DIR)
VPATH = $(SRC_FILES)
tear_abc123: $(OBJ)/ur23.o
$(CC) $(CFLAGS) -c $(subst tear_,,$#.c) $#.c $#_compiletime.c -o $#
In this, $#_compiletime.c (say tear_abc123_compiletime.c) gets generated before $(CC). make throws an error that abc123.c is not found. where abc123.c is present in $(ABC_DIR). Why vpath is could not find the c file.
The main problem is that VPATH works only for Prerequisites. And it does not work from the 'command' part of the target.
To make VPATH work you should specify list of sources in Prerequisites and reference it in the command using $^.
Please see the following example (for file tree as below)
.
|-- abc
| |-- abc123.c
| |-- tear_abc123.c
| `-- tear_abc123_compiletime.c
`-- Makefile
Makefile contains
SRC_DIRS := abc
VPATH := $(SRC_DIRS)
TARGET := tear_abc123
SOURCE_FILES := $(TARGET).c $(TARGET)_compiletime.c $(subst tear_,,$(TARGET).c)
tear_abc123: $(SOURCE_FILES)
#echo "SOURCE_FILES := $(SOURCE_FILES)"
#echo "prerequisites = $^"
The output will be
$ make
SOURCE_FILES := tear_abc123.c tear_abc123_compiletime.c abc123.c
prerequisites = abc/tear_abc123.c abc/tear_abc123_compiletime.c abc/abc123.c
As you can see
the SOURCE_FILES really contains only source files names
the prerequisites is automatically substituted with correct path
I have a project that has many makefiles inside it. Because sometimes I need to compile only some parts of my project so I decided to have one makefile in each directory. But when I want to run the main makefile that includes all other ones to compile my project it gives me lots of errors.
This is my project tree:
root 'makefile'
-folder1 'foo1.c foo2.c makefile'
-folder2 'makefile'
--folder2-1 'foo3.c foo4.c makefile'
--folder2-2 'foo5.c makefile'
Each makefile in the very last directory has been included to it's upper makefile. But it doesn't run the main makefile. I'm really new to GNU make and I want to have something like this but I don't know how. I just wrote some make scripts but it doesn't work.
I just want to have something that I can compile the projects parts separately or compile the whole project using multiple makefiles.
any way, I show you something and hope can help you:
all:
#$(MAKE) -C subfolder
or if you want to use *.mk as your sub makefile, you can write:
all:
#$(MAKE) -C busfolder -f somename.mk
I show you my example, my DIR looks like:
TOPDIR-- Makefile
|
|-- debug
| |-- debug.c
| |-- debug.h
| |-- debug.mk
| |-- instrument.c
| `-- uart_print.c
|-- driver
| |-- driver.c
| |-- driver_ddi.c
| |-- driver_ddi.h
| |-- driver.h
| `-- driver.mk
|-- include
| `-- common.h
|-- Makefile
|-- mw
| |-- manager.c
| `-- mw.mk
|-- root
| |-- main.c
| `-- root.mk
and my TOP makefile looks like:
MAKE_DIR = $(PWD)
ROOT_DIR := $(MAKE_DIR)/root
DRV_DIR := $(MAKE_DIR)/driver
INCLUDE_DIR := $(MAKE_DIR)/include
DEBUG_DIR := $(MAKE_DIR)/debug
INC_SRCH_PATH :=
INC_SRCH_PATH += -I$(ROOT_DIR)
INC_SRCH_PATH += -I$(DRV_DIR)
INC_SRCH_PATH += -I$(INCLUDE_DIR)
INC_SRCH_PATH += -I$(DEBUG_DIR)
LIB_SRCH_PATH :=
LIB_SRCH_PATH += -L$(MAKE_DIR)/libs
COLOR_ON = color
COLOR_OFF =
CC = $(COLOR_ON)gcc
#CC = $(COLOR_OFF)gcc
LD = ld
LINT = splint
LIBS := -ldriver -ldebug -lmw -lm -lpthread
CFLAGS :=
CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH)
CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand
CFLAGS += -DDEBUG -D_REENTRANT
LDFLAGS :=
export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH
all:
#$(MAKE) -C debug -f debug.mk
#$(MAKE) -C driver -f driver.mk
#$(MAKE) -C mw -f mw.mk
#$(MAKE) -C root -f root.mk
.PHONY: clean
clean:
#$(MAKE) -C debug -f debug.mk clean
#$(MAKE) -C driver -f driver.mk clean
#$(MAKE) -C mw -f mw.mk clean
#$(MAKE) -C root -f root.mk clean
it will call sub DIR *.mk during the compile. The sub DIR makefile, I just write a simple example for you reference:
LIB = $(MAKE_DIR)/libs/yourmodulename.a
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
$(LIB): $(OBJS)
#mkdir -p ../libs
#$(AR) cr $# $^
#echo " Archive $(notdir $#)"
$(OBJS): $(SRCS)
#$(CC) $(CFLAGS) -c $^
#echo " CC $(OBJS)"
.PHONY: clean
clean:
#$(RM) -f $(LIB) $(OBJS)
#$(RM) -f *.expand
#echo " Remove Objects: $(OBJS)"
for the makefile, which generate the final target file(like a.out) is little bit different, because I use the sub makefile to generate LIB file, and I use a root.mk to generate final target:
PROG = ../prog/DEMO
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
$(PROG): $(SRCS)
#mkdir -p ../prog
#$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $#
#echo " Generate Program $(notdir $(PROG)) from $^"
.PHONY: clean
clean:
#$(RM) -f $(OBJS) $(PROG)
#$(RM) -f *.expand
#$(RM) -rf ../prog ../libs
#echo " Remove Objects: $(OBJS)"
#echo " Remove Libraries: $(notdir $(PROG))"
In continuation with my earlier question
Makefile - compiling back and forth
I made an attempt in creating a single Makefile. The two subdirectories are HAM-src and GFS-src. However, I am still unable to build it. I paste my Makefile below:
export
SHELL = /bin/sh
top_srcdir=./Temp
objdir=$(top_srcdir)/obj
bindir=${exec_prefix}/bin
cfssrcdir=${top_srcdir}/GFS-src
hamsrcdir=${top_srcdir}/HAM-src
incdir=${top_srcdir}/include
exec=${bindir}/esm_gfs-ham_v0
PROG=$(exec)
LDR = mpxlf90_r -qsmp=noauto
FFLAG90 = $(OPTS90) $(FINCS) -qfree=f90 -NS2048 -qmoddir=$(objdir) -I$(objdir)
FFLAGM = -NS2048 -qfixed -qmoddir=$(objdir) -I$(objdir)
F77 = mpxlf95
F90 = mpxlf95
F90_x = xlf90_r
F90_r = mpxlf95_r
SRCHAM = $(hamsrcdir)/ham_control.f90 $(hamsrcdir)/mo_filename.f90 \
$(hamsrcdir)/ham_namelist.f90 $(hamsrcdir)/ham_submodel.f90 \
$(hamsrcdir)/ham_submodel_diag.f90 $(hamsrcdir)/ham_ham.f90
SRCGFS_MOD=$(cfssrcdir)/machine.f $(cfssrcdir)/resol_def.f \
$(cfssrcdir)/omegas.f $(cfssrcdir)/cnvcld_v.f
OBJGFS_MOD = $(patsubst $(cfssrcdir)/%.f,$(objdir)/%.o,$(SRCGFS_MOD))
OBJHAM = $(patsubst $(hamsrcdir)/%.f90,$(objdir)/%.o,$(SRCHAM))
.SUFFIXES: $(SUFFIXES) .f90 .f .o
all: $(PROG)
$(PROG): $(OBJHAM) $(OBJGFS_MOD)
$(LDR) $(CFS_LDFLAGS) -o $# $(OBJGFS_MOD) $(OBJHAM) $(CFS_LIBS) -L$(LDFLAGS)
$(objdir)/%.o: $(cfssrcdir)/%.f
$(F77) $(FFLAGS) -c $< -o $#
$(objdir)/%.o: $(hamsrcdir)/%.f90
$(F90_r) $(F90FLAGS) -c $< -o $#
########## dependencies for $(hamsrcdir) ###########
ham_filename.o: ham_control.o
ham_namelist.o: ham_control.o ham_filename.o
ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
ham_submodel_diag.o: ham_submodel.o
########## dependencies for $(cfssrcdir) ###########
$(objdir)/omegas.o: $(cfssrcdir)/omegas.f
$(F77) $(FFLAGM) -c $(cfssrcdir)/omegas.f -o $#
$(objdir)/cnvcld_v.o: $(cfssrcdir)/cnvcld_v.f
$(F77) $(FFLAGM) -c $(cfssrcdir)/cnvcld_v.f -o $#
The error:
mpxlf95_r -q64 -O3 -qstrict -qMAXMEM=-1 -qarch=auto -qtune=auto -qcache=auto -qfloat=fltint -qsuffix=cpp=f90 -lessl_r -lmass -lmassv -I./Temp/include -I./Temp/HAM-src -qmoddir=./Temp/obj -I./Temp/obj -c ./Temp/HAM-src/ham_namelist.f90 -o ./Temp/obj/ham_namelist.o
** ham_namelist === End of Compilation 1 ===
1501-510 Compilation successful for file ham_namelist.f90.
mpxlf95_r -q64 -O3 -qstrict -qMAXMEM=-1 -qarch=auto -qtune=auto -qcache=auto -qfloat=fltint -qsuffix=cpp=f90 -lessl_r -lmass -lmassv -I./Temp/include -./Temp/HAM-src -qmoddir=./Temp/obj -I./Temp/obj -c ./Temp/HAM-src/ham_submodel.f90 -o ./Temp/obj/ham_submodel.o
"./Temp/HAM-src/ham_submodel.f90", line 425.7: 1514-219 (S) Unable to access module symbol file for module resol_def. Check path and file permissions of file. Use association not done for this module.
1501-511 Compilation failed for file ham_submodel.f90.
gmake: *** [/gpfs1/home/cccrmod/ham_expt_dec11/regrid_test/CFS-HAM/SORC_CFS-HAM/Temp/obj/ham_submodel.o] Error 1
Why makefile does not compile the resol_def.f module on encountering the dependency?
Another issue - my makefile is not working properly. It goes in a sequence in which the sources are defined.
This is difficult to untangle (a minimal, complete example really would help), but I'd suggest you change this
ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
to this
$(objdir)/ham_submodel.o: ham_control.o ham_namelist.o $(objdir)/resol_def.o
and see if that solves the first problem. I don't understand the last line of your question ("Another issue...").