As you can see in this GitHub repo, I downloaded a solution from NIST Random Number Generator Test Suite that contains a makefile and C files in the subdirectories.
According to pg 96 of the documentation provided, I have to run make and then run assess 100 (or any other number). I was able to successfully run make but I can't seem to run assess 100, as it just says "command not found". It's supposed to display this I believe:
I tried to go through this makefile tutorial but I wasn't able to understand what's going on. What do I do?
Here's the top snippet of the makefile, if it helps:
CC = /usr/bin/gcc
GCCFLAGS = -c -Wall
ROOTDIR = .
SRCDIR = $(ROOTDIR)/src
OBJDIR = $(ROOTDIR)/obj
VPATH = src:obj:include
OBJ = $(OBJDIR)/assess.o $(OBJDIR)/frequency.o $(OBJDIR)/blockFrequency.o \
$(OBJDIR)/cusum.o $(OBJDIR)/runs.o $(OBJDIR)/longestRunOfOnes.o \
$(OBJDIR)/serial.o $(OBJDIR)/rank.o $(OBJDIR)/discreteFourierTransform.o \
$(OBJDIR)/nonOverlappingTemplateMatchings.o \
$(OBJDIR)/overlappingTemplateMatchings.o $(OBJDIR)/universal.o \
$(OBJDIR)/approximateEntropy.o $(OBJDIR)/randomExcursions.o \
$(OBJDIR)/randomExcursionsVariant.o $(OBJDIR)/linearComplexity.o \
$(OBJDIR)/dfft.o $(OBJDIR)/cephes.o $(OBJDIR)/matrix.o \
$(OBJDIR)/utilities.o $(OBJDIR)/generators.o $(OBJDIR)/genutils.o
assess: $(OBJ)
$(CC) -o $# $(OBJ) -lm
$(OBJDIR)/assess.o: $(SRCDIR)/assess.c defs.h decls.h utilities.h
$(CC) -o $# -c $(SRCDIR)/assess.c
...
Related
I'm trying to port my wayland compositor from make to scons, but I'm having trouble with the build order. I need xdg-shell-protocol to be generated with wayland-scanner and built before anything else. With make, something like this is all it takes:
WLSCAN_INFO = #echo " WLSCAN " $#;
CC_INFO = #echo " CC " $#;
CFLAGS= -g \
-Werror \
-I. \
-DWLR_USE_UNSTABLE
LIBS = "-Lxdg-shell-protocol.h" \
$(shell pkg-config --cflags --libs wlroots) \
$(shell pkg-config --cflags --libs wayland-server) \
$(shell pkg-config --cflags --libs xkbcommon) \
WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
XDG_SHELL_DEPS = xdg-shell-protocol.c xdg-shell-protocol.h
xdg-shell-protocol.h:
$(WLSCAN_INFO)$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $#
xdg-shell-protocol.c: xdg-shell-protocol.h
$(WLSCAN_INFO)$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $#
OBJS = \
xdg-shell-protocol.o \
output.o \
renderer.o \
input.o \
xdg.o \
cursor.o \
keyboard.o \
main.o
%.o: %.c xdg-shell-protocol.h
$(CC_INFO)$(CC) $(CFLAGS) -c $(LIBS) -o $# $<
wlc: $(OBJS)
$(CC_INFO)$(CC) $(CFLAGS) $(LIBS) -o $# $(OBJS)
clean:
rm -f wlc $(XDG_SHELL_DEPS) *.o
.DEFAULT_GOAL = wlc
.PHONY: wlc clean
With scons, I tried this:
CCFLAGS = "-fdiagnostics-color=always -g -Werror -DWLR_USE_UNSTABLE"
CPPPATH = ["./", "./include"]
env = Environment()
env.Append(CCFLAGS = CCFLAGS)
env.Append(CPPPATH = ["./", "./include"])
env.ParseConfig("pkg-config --cflags --libs wlroots")
env.ParseConfig("pkg-config --cflags --libs wayland-server")
env.ParseConfig("pkg-config --cflags --libs xkbcommon")
env.Command( source = "",
target = "xdg-shell-protocol.h",
action = "`pkg-config --variable=wayland_scanner wayland-scanner` server-header \
`pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml \
$TARGET"
)
env.Command( source = "",
target = "xdg-shell-protocol.c",
action = "`pkg-config --variable=wayland_scanner wayland-scanner` private-code \
`pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml \
$TARGET"
)
xdg_shell_protocol = env.Library(
target = "xdg-shell-protocol",
source = [
"xdg-shell-protocol.h",
"xdg-shell-protocol.c"
]
)
wlc = env.Program(
target = "wlc",
source = [
Glob("input/*"),
Glob("output/*"),
Glob("shell/*"),
"main.c",
],
LIBS=[xdg_shell_protocol], LIBPATH="."
)
env.Depends(wlc, "xdg-shell-protocol.h")
)
But wlc always gets built before xdg_shell_protocol, and ends up failing because xdg-shell-protocol.h hasn't been generated yet. I also tried:
Defining an explicit dependency by adding env.Depends(wlc, "xdg-shell-protocol.h") or env.Depends(wlc, xdg_shell_protocol) at the end,
Setting LIBS = ["xdg-shell-protocol"] in wlc,
Not using Library and just adding xdg-shell-protocol.h and xdg-shell-protocol.c to the beginning of source in wlc.
But main.c or some other source file always ends up being compiled first and fails because xdg-shell-protocol.h doesn't exist yet.
What am I doing wrong?
EDIT:
Expanded ... above (note that the makefile is from before I moved source files to subdirectories, which was the main reason I decided to change build systems).
Output of $ scons --tree=prune
Please post the full file, the '...''s may be relevant.
Do any of your Command()'s specify the source argument?
What's line 1 of: include/shell/xdg.h ?
try adding this line
env.Depends('input/cursor.c', 'xdg-shell-protocol.h')
NOTE: This is not a good solution, but will help figure out what the issue is.
Now.. Try changing your Program(..) to this, and remove your explicit Depends().
cpppath = env['CPPPATH'] + ['/usr/include']
wlc = env.Program(
target = "wlc",
source = [
Glob("input/*"),
Glob("output/*"),
Glob("shell/*"),
"main.c",
],
LIBS=[xdg_shell_protocol],
CPPPATH=cpppath,
)
The problem is caused by the source scanner not seeing the dependency on xdg-shell-protocol.h because it comes from including /usr/include/wlr/types/wlr_xdg_shell.h, which wouldn't normally be scanned (this was the genesis of the suggestion above to add /usr/include to CPPPATH but that didn't seem to be good enough), and thus you don't get the order you would - forcing that header to get generated early - if it noticed that dependency. From your workaround, I think you can simplify to just this:
env.Depends("include/shell/xdg.h", "xdg-shell-protocol.h")
Which may still end up not being the prettiest answer...
Apparently I have to define the explicit dependency for each source file:
wlc_source = [
"main.c",
Glob("input/*.c"),
Glob("output/*.c"),
Glob("shell/*.c"),
]
for source in wlc_source:
env.Depends(source, xdg_shell_protocol)
wlc = env.Program(
target = "wlc",
source = wlc_source
)
This fixes the issue, but I don't think this is the best solution.
I use opencv in my project, and now I compile the project into a static library using makefile, but always output 'fatal error: 'cv.h' file not found'. I have searched this site and elsewhere, it's not what I need. I only know a little makefile syntax. What should I do?
Makefile
LIBS_DIR = ./lib/
OBJS_DIR = ./obj/
DEPENDENT_DIR = ./dependent/
HEADER_PATH = -I./include -I./implement -I.
LIB_PATH = -L./lib
SRCDIRS := $(patsubst ./%, %, $(shell find . -type d))
SRCS_CXX := $(foreach dir, $(SRCDIRS), $(wildcard $(addprefix $(dir)\/*, .cpp)))
OBJS := $(SRCS_CXX:.cpp=.o)
%.o: %.cpp
#echo "---------- .o begin ----------"
$(CXX) -c $< $(HEADER_PATH)
$(CXX) -o $# $^ $(LIB_PATH)
mv $# $(OBJS_DIR)
%.d: %.cpp
#echo "---------- dependent begin ----------"
#set -e; \
rm -f $#; \
$(CXX) -MM $< > $#.tmp; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.tmp > $#; \
rm -f $#.tmp
mv $# $(DEPENDENT_DIR)
-include $(DEPS)
.PHONY: clean
clean:
rm -f obj/*.o lib/*.a dependent/*.d
rm -rf SunWS_cache
In my file
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
File directory
Used makefile
New error
I modified the HEADER_PATH like HEADER_PATH = -I./include/opencv -I./include/opencv2 -I./implement -I. but a new error appeared, fatal error: 'opencv2/core/core_c.h' file not found.
I try to add a new subfolder path like -I./include/opencv -I./include/opencv2 -I./include/opencv2/core -I./implement -I. this error is still being output, -I command doesn't automatically find the path to the subfolder? am I doing anything wrong?
Your header paths are HEADER_PATH = -I./include -I./implement -I.
Inside the include folder you show in the attachment you have 2 subfolders opencv and opencv2.
When including the cv.h file is included directly without the subfolders.
For the compiler to find the files you either need to add the subfolders on the HEADER_PATH like HEADER_PATH = -I./include/opencv -I./include/opencv2 -I./implement
or you need to #include <opencv/cv.h>, that if cv.h is directly inside the opencv subfolder.
Side note: you have a typo in the folder denpendent
Finally, I solved this error and compiled successfully, I still use CMake. but after I successfully compiled with CMake, I can use the Makefile again to compile. I think it was my own mistake, #zomeck's answer helped me.
This is my CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(library_name)
add_definitions(-Wall)
set(OPENCV_PATH ../sdk3/opencv3.0.0)
set(OPENCL_PATH ../sdk3/opencl)
link_directories(
${OPENCL_PATH}/bin
${OPENCV_PATH}
)
link_libraries(
${OPENCV_PATH}/opencv2.framework
${OPENCL_PATH}/bin/OpenCL.DLL
)
include_directories(
./
./implement
${OPENCV_PATH}/include
${OPENCV_PATH}/include/opencv
${OPENCL_PATH}/include/CL
)
set(SOURCES_FILES
HS_Process.cpp
implement/iclear/H_Proc.cpp
)
add_library(library_name STATIC ${SOURCES_FILES})
target_link_libraries(library_name opencv2 OpenCL)
New Makefile after #zomeck's answer
# The following is modified
SDK_PATH = ../sdk3
OPENCL_PATH = ../sdk3/opencl
OPENCV_PATH = ../sdk3/opencv3.0.0/include
vpath = %.h implement : %.h $(OPENCV_PATH) : %.h $(OPENCV_PATH)/opencv : %.h $(OPENCL_PATH) : %.h $(CALCTIME_PATH)
HEADER_PATH = \
-I. \
-I./implement \
-I$(OPENCV_PATH) \
-I$(OPENCV_PATH)/opencv \
-I$(OPENCV_PATH)/opencv2 \
-I$(OPENCL_PATH)/include/CL \
%.o: %.cpp
#echo "---------- .o begin ----------"
$(CXX) $(CXXFLAGS) -c $(HEADER_PATH) $< -o $#
mv $# $(OBJS_DIR)
Good day,
recently i switched from jamfile to makefile. The reason of this switch is that i think that jamfile does not really cooperate with armadillo and openmp libraries. I have code divided into multiple *.h and *.cpp files.
# makefile for my PhD thesis
# Created by Michal Buday, no copyrights
# Datum: 01.07.2016
SHELL := /bin/sh
SRC := methods
BIN := bin
CXX := g++ # GNU C++ compiler
CXXFLAGS := -Wall
ARMAF := -larmadillo # ARMADILLO matrix library
OPT := -O
# GGG := -g # for debugging
# bash$ gdp ${program name} core
# ===============================================================================================
# standard stuff
all: coord_trans.o geodetic_functions.o geo_models.o interpolations.o \
legendre.o loadpoints.o physical_constants.o sphere_int.o \
3Dtransformations.o
LIBOBJ = coord_trans.o geodetic_functions.o geo_models.o interpolations.o \
legendre.o loadpoints.o physical_constants.o sphere_int.o \
3Dtransformations.o #topo_corrections.o
geodetic_functions.o: $(SRC)/geodetic_functions.h
$(CXX) $(OPT) -c $(SRC)/geodetic_functions.h -o $(BIN)/$#
geo_models.o: $(SRC)/geo_models.h $(SRC)/legendre.h $(SRC)/geodetic_functions.h \
$(SRC)/physical_constants.h
$(CXX) $(OPT) -c $(SRC)/geo_models.h -o $(BIN)/$#
interpolations.o: $(SRC)/interpolations.cpp $(SRC)/interpolations.h
$(CXX) $(OPT) -c $(SRC)/interpolations.cpp -o $(BIN)/$#
legendre.o: $(SRC)/legendre.h
$(CXX) $(OPT) -c $(SRC)/legendre.h -o $(BIN)/$#
loadpoints.o: $(SRC)/loadpoints.h
$(CXX) $(OPT) -c $(SRC)/loadpoints.h -o $(BIN)/$#
sphere_int.o: $(SRC)/sphere_int.h $(SRC)/sphere_int.cpp
$(CXX) $(OPT) -c $(SRC)/sphere_int.cpp $(ARMAF) -o $(BIN)/$#
#topo_corrections.o: $(SRC)/topo_corrections.h $(SRC)/geodetic_functions.h
# $(CXX) $(OPT) -c $(SRC)/topo_corrections.h $(ARMAF)
3Dtransformations.o: $(SRC)/3Dtransformations.h $(SRC)/3Dtransformations.cpp
$(CXX) $(OPT) -c $(SRC)/3Dtransformations.cpp $(ARMAF) -o $(BIN)/$#
coord_trans.o: $(SRC)/coord_trans.h $(SRC)/geodetic_functions.h
$(CXX) $(OPT) -c $(SRC)/coord_trans.h -o $(BIN)/$#
main.o: $(LIBOBJ)
$(CXX) $(OPT) $(BIN)/$(LIBOBJ) -o $# $(ARMAF)
# ======================================================================== #
#
clean:
rm *.o
The dependencies are:
# coord_trans.h << geodetic_functions.h
# geodetic_functions.h << armadillo
# geo_models.h << legendre.h geodetic_functions.h physical_constants.h
# interpolations.h << std
# legendre.h << std
# loadpoints.h << std
# physical_constants.h << define only
# sphere_int.h << armadillo
# topo_corrections.h << geodetic_functions.h
# 3Dtransformations.h << armadillo
But when i call
make
in terminal it creates only the first 3 entries in makefile and also the size of binary files is over 107 MB (the code itself has 100k or less). What am i missing?
Thank you for any advices.
First of all, you may want to use $< (first dependancie) for your -c argument instead of repeating it.
Also, I would advise to build the list of object files given the cpp files (wildcard function?).
Finally, you may want to try to replace $(BIN)/$(LIBOBJ) by $(FULLPATH_LIBOBJ) constructed using:
FULLPATH_LIBOBJ = $(addprefix $(BIN)/, $(LIBOBJ))
Not sure this changes anything, but your makefile looks complicated to me, whereas it should be much simpler!
Also, it is hard to help you compiling the project without the project itself.
I am new to using CMake and am attempting to transfer our previous Makefiles into CMakeLists. I have one file, *dsplink_defines.txt* that has the following compile-time defines.
*-DOS_LINUX -DMAX_DSPS=1 -DMAX_PROCESSORS=2 -DID_GPP=1 -DOMAPL1XX -DPROC_COMPONENT -DPOOL_COMPONENT -DNOTIFY_COMPONENT -DMPCS_COMPONENT -DRINGIO_COMPONENT -DMPLIST_COMPONENT -DMSGQ_COMPONENT -DMSGQ_ZCPY_LINK -DCHNL_COMPONENT -DCHNL_ZCPY_LINK -DZCPY_LINK -DKFILE_DEFAULT -DDA8XXGEM -DDA8XXGEM_PHYINTERFACE=SHMEM_INTERFACE -DGPP_SWI_MODE -D_REENTRANT -DVERIFY_DATA -DDDSP_DEBUG*
Our previous Makefile took care of this in the following manner and took care of this by using shell cat starting on line 8:
BIN = ../../build/bin
TMP = build
BUILD_DEF = -DBUILD=$(BUILD_VERSION) -DBUILD_DATE=$(BUILD_DATE)
# these files are captured from the DSPLink Sample build directory (and the named changed)
# they contain the appropriate includes and flags to build a dsplink application.
DSPLINK_INCLUDES = $(shell cat ../dsplink_config/dsplink_includes.txt)
DSPLINK_FLAGS = $(shell cat ../dsplink_config/dsplink_flags.txt)
DSPLINK_DEFINES = $(shell cat ../dsplink_config/dsplink_defines.txt)
DSPLINK_LIBS = $(DSPLINK_PACKAGE_DIR)/dsplink/gpp/export/BIN/Linux/OMAPL1XX/RELEASE/dsplink.lib
#Our project variables
INCLUDE = -I../framework -I../io_master -I../logging -I../../dsp/include - I../flagDictionary
#TOOLCHAIN = ${FACTORY_DIR}/build_armv5l-timesys-linux-uclibcgnueabi/toolchain/bin
TOOLCHAIN = /OMAP-L137/timesys/SDK/omapl137_evm/toolchain/bin
PLATFORM=armv5l-timesys-linux-uclibcgnueabi
#Compile Options
CC=$(TOOLCHAIN)/$(PLATFORM)-g++
LINKER=$(TOOLCHAIN)/$(PLATFORM)-g++
CFLAGS+= $(BUILD_DEF) $(INCLUDE) $(DSPLINK_DEFINES) $(DSPLINK_FLAGS) $(DSPLINK_INCLUDES)
DEBUG = -O
#list of things to compile.
FW_BUILD_DIR=../framework/build
LOG_BUILD_DIR=../logging/build
FLAG_DICT_BUILD_DIR=../flagDictionary/build
FRAMEWORK_OBJECTS= $(FW_BUILD_DIR)/com.o \
$(FW_BUILD_DIR)/application.o \
$(FW_BUILD_DIR)/memoryManagerBase.o \
$(FW_BUILD_DIR)/memoryManager.o \
$(FW_BUILD_DIR)/arguments.o \
$(FW_BUILD_DIR)/lockManager.o \
$(FW_BUILD_DIR)/controlCom.o \
$(FW_BUILD_DIR)/paths.o \
$(LOG_BUILD_DIR)/subsystemLogMasks.o \
$(LOG_BUILD_DIR)/logger.o
FLAG_DICT_OBJECTS= $(FLAG_DICT_BUILD_DIR)/flagEntry.o \
$(FLAG_DICT_BUILD_DIR)/flagDictionary.o
OBJECTS = spidev_test.o sysMon.o
EXES = sysMon
all: $(OBJECTS) $(EXES)
.c.o:
mkdir -p build
$(CC) -c $(CFLAGS) $(DEBUG) -o $(TMP)/$# $<
.cpp.o:
mkdir -p build
$(CC) -c $(CFLAGS) $(DEBUG) -o $(TMP)/$# $<
spidev_test: $(FRAMEWORK_OBJECTS) spidev_test.o
$(LINKER) -lpthread -lc -o $(BIN)/$# $(DSPLINK_LIBS) build/spidev_test.o $(FRAMEWORK_OBJECTS)
sysMon: $(FRAMEWORK_OBJECTS) sysMon.o
$(LINKER) -lpthread -lc -o $(BIN)/$# $(DSPLINK_LIBS) build/sysMon.o $(FLAG_DICT_OBJECTS) $(FRAMEWORK_OBJECTS)
deploy:
../../build/deploy
How do I pass these in using a CMakeList
This should work:
file(READ path/to/dsplink_defines.txt defines) #read file into variable 'defines'
string(REPLACE " " ";" defines "${defines}") #turn space separation into CMake list
add_definitions(${defines})
Of course, if you have full control of the file and can change its format to use semicolons for separation instead of spaces, you can do that and skip the string() line (probably speeding up your CMake processing a little bit by this).
I am not very familiar with make; i've always used and modified this highly ancient makefile I inherited from another project, modifying it as necessary. Up until now, it has functioned perfectly, compiling together projects with 20-50 files, even within sub-directories, determining and building all the dependencies properly.
Today I am running a very simple test code to determine if BOOST.MPI will work on a cluster I recently got access to. I am trying to compile a 1-file test case to make sure that the library works. This is also my first time building and linking to boost on this system.
I have boost installed in my user directory: ~/boost, and I've run the appropriate bjam to ensure that BOOST.MPI is present. I don't believe my problem lies there. As you'll see in a moment, however, I had to include -lboost_mpi and -lboost_serialization to get as far as I did.
The makefile seems to compile, and assemble just fine producing the intermediary .a file. It hangs up on the linking step with a surprising error:
Creating dependency for "boosttest.cpp"
Compiling "boosttest.cpp"
Assembling ag...
ar: creating ./libag.a
Linking bt1...
/usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [bt1] Error 1
The only source code I've written (copy/pasted right out of the Boost.MPI implementation page):
boosttest.cpp:
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::mpi::environment env(argc, argv);
boost::mpi::communicator world;
std::cout << "I am process " << world.rank() << " of " << world.size()<< "." << std::endl;
return 0;
}
Now for the part where I get lost. This is the makefile I've modified. I mostly understand what parts of it are doing, and it is the only makefile I've ever seen (although as mentioned I'm not very experienced with them) to produce .d files containing a list of all dependent libraries.
Makefile:
PROJECT = boosttest
# The names of the sub-projects that the executable depends on. These names are used later on to define targets, location, libraries, etc.
DEPS =
# The names of the sub-projects that the test executable depends on.
TEST_DEPS =
EXE_DEPS =
LOCAL_O_FILES = boosttest.o
LOCAL_TEST_O_FILES =
LOCAL_LIB_NAME = ag
LOCAL_LIB_DIR = .
LOCAL_TEST_LIB_NAME =
LOCAL_TEST_LIB_DIR =
LOCAL_INCLUDE_ROOT = .
EXE_NAME = BT
MPIC_DIR = /usr/local/mvapich2-1.6-gcc/
#these assume our local path and bin are set up properly since I don't know where the compilers are
CC = $(MPIC_DIR)/bin/mpicc
CCC = $(MPIC_DIR)/bin/mpicxx
F77 = $(MPIC_DIR)/bin/mpif77
CLINKER = $(MPIC_DIR)/bin/mpicc
CCLINKER = $(MPIC_DIR)/bin/mpicxx
FLINKER = $(MPIC_DIR)/bin/mpif90
F90 = $(MPIC_DIR)/bin/mpif90
F90LINKER = $(MPIC_DIR)/bin/mpif90
MAKE = make --no-print-directory
SHELL = /bin/sh
#PROF = -ggdb -O2
PROF = -O2
ADDITIONAL_LIBS = -lboost_mpi -lboost_serialization
SED = $(shell which sed)
GREP = $(shell which grep)
# Warnings will depend on the GCC version -- if it's 4, have "-Wdeclaration-after-statement -Wunused-value -Wunused-variable"
#GCC_MAJOR_VERSION = $(shell $(CCC) --version | $(GREP) "\(egcs\|gcc\)" | $(SED) "s/[^0-9]*\([0-9]\).*/\1/")
#WARNINGS = -Wno-import $(shell if test $(GCC_MAJOR_VERSION) -eq 4; then echo -Wunused-value -Wunused-variable; fi)
#GCC_INSTALL_DIR = /turing/software-linux/mpich-eth
GCC_INSTALL_DIR = $(MPIC_DIR)
GCC_INCLUDE_DIR = $(GCC_INSTALL_DIR)/include/
GCC_LIB_DIR = $(GCC_INSTALL_DIR)/lib/
BOOST_DIR = ~/boost
BOOST_LIB_DIR = ~/boost/stage/lib
# Expand SRCDIR so that it turns into "-I <srcdir>" for each listed directory
INCLUDE_DIRS = -I $(OBJC_ROOT)/include $(foreach dep, $(UNIQUE_DEPS), -I$($(dep)_INCLUDE_ROOT)) -I $(LOCAL_INCLUDE_ROOT) -I $(BOOST_DIR) -I $(GCC_INCLUDE_DIR)
#C_FLAGS = -DROM $(PROF) $(WARNINGS) $(INCLUDE_DIRS)
C_FLAGS = -DROM $(PROF) $(INCLUDE_DIRS)
L_FLAGS = $(foreach dir, $(OBJC_ROOT) $(DEP_LIB_DIRS), -L$(dir)) -L $(BOOST_LIB_DIR) -L $(GCC_LIB_DIR) $(PROF) $(ADDITIONAL_LIBS)
TEST_L_FLAGS = $(foreach dir, $(OBJC_ROOT) $(TEST_DEP_LIB_DIRS), -L$(dir)) -L/usr/lib -Xlinker --whole-archive $(TEST_REQUIRED_LIBS) -Xlinker --no-whole-archive
REQUIRED_LIBS = $(foreach dep, $(DEPS) LOCAL, $(if $($(dep)_LIB_NAME), -l$($(dep)_LIB_NAME)))
TEST_REQUIRED_LIBS = $(foreach dep, $(TEST_DEPS) LOCAL LOCAL_TEST, $(if $($(dep)_LIB_NAME), -l$($(dep)_LIB_NAME)))
.SUFFIXES:
.SUFFIXES: .d .cc .cpp .c .o
ASSEMBLE_TARGETS = $(foreach dep,$(DEPS),$(dep)_LIB_NAME)
ASSEMBLE_TEST_TARGETS = $(foreach dep,$(TEST_DEPS),$(dep)_LIB_NAME)
CLEAN_TARGETS = $(foreach dep, $(UNIQUE_DEPS), $(dep)_CLEAN)
LOCAL_D_FILES = $(LOCAL_O_FILES:.o=.d)
LOCAL_TEST_D_FILES = $(LOCAL_TEST_O_FILES:.o=.d) $(TEST_RUNNER:.o=.d)
DEP_LIB_DIRS = $(foreach dep, $(DEPS) LOCAL, $($(dep)_LIB_DIR))
TEST_DEP_LIB_DIRS = $(foreach dep, $(TEST_DEPS) LOCAL LOCAL_TEST, $($(dep)_LIB_DIR))
UNIQUE_ASSEMBLE_TARGETS = $(sort $(ASSEMBLE_TARGETS) $(ASSEMBLE_TEST_TARGETS))
UNIQUE_DEPS = $(sort $(DEPS) $(TEST_DEPS))
LOCAL_LIB = $(if $(LOCAL_LIB_NAME), $(LOCAL_LIB_DIR)/lib$(LOCAL_LIB_NAME).a)
LOCAL_TEST_LIB = $(if $(LOCAL_TEST_LIB_NAME), $(LOCAL_TEST_LIB_DIR)/lib$(LOCAL_TEST_LIB_NAME).a)
EXE_TARGETS = $(foreach dep,$(EXE_DEPS),$(dep)_EXE_NAME)
INSTALL_TARGETS = $(foreach dep,$(EXE_DEPS),$(dep)_INSTALL)
export PROJECTS += $(PROJECT)
# PHONY targets get remade even if there exists an up-to-date file with the same name.
.PHONY: default clean compile assemble link submit
# Targets for mortals
default: link
clean: $(CLEAN_TARGETS) LOCAL_CLEAN
compile: $(DEPS) $(LOCAL_D_FILES) $(LOCAL_O_FILES)
assemble: compile $(ASSEMBLE_TARGETS) $(LOCAL_LIB)
link: assemble $(EXE_TARGETS) $(EXE_NAME)
install: $(INSTALL_TARGETS) $(if $(EXE_NAME), LOCAL_INSTALL)
submit: link
qsub $(PROJECT).qsub
# Targets for make
# Invoking sub projects
$(UNIQUE_DEPS): MAKE_TARGET = $(if $(filter %_TEST, $#), compile-tests, compile)
$(UNIQUE_DEPS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($#_DIR) && $(MAKE) $(MAKE_TARGET))
# First, remove the _LIB_NAME attached by ASSEMBLE_TARGETS, a
$(UNIQUE_ASSEMBLE_TARGETS): DEP_NAME = $(#:_LIB_NAME=)
$(UNIQUE_ASSEMBLE_TARGETS): MAKE_TARGET = $(if $(filter %_TEST, $(DEP_NAME)), assemble-tests, assemble)
$(UNIQUE_ASSEMBLE_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) $(MAKE_TARGET))
# First, remove the _EXE_NAME attached by EXE_TARGETS, a
$(EXE_TARGETS): DEP_NAME = $(#:_EXE_NAME=)
$(EXE_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) link)
$(CLEAN_TARGETS): DEP_NAME = $(#:_CLEAN=)
$(CLEAN_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) clean)
$(INSTALL_TARGETS): DEP_NAME = $(#:_INSTALL=)
$(INSTALL_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) install)
#Local stuff
# The rule to change either a '.c' or a '.m' to a '.o'
#%.o : %.c %.d %.cc %.cpp
.cc.o .cpp.o .c.o:
#echo "Compiling \"$<\""
#$(CCC) -c $(C_FLAGS) $< -o $#
.cc.d .cpp.d .c.d :
#echo "Creating dependency for \"$<\""
# #$(CCC) $(WARNINGS) $(INCLUDE_DIRS) -MM $< -o $#
# This foogly hack because gcc seems to have issues with emitting the correct target/dependency names of
# files in sub-dirs of the current dir (specifically, it doesn't add the sub-dir to the target
# name, and insists on adding the directory to the dependencies) which ends up breaking dependencies...)
#dependLine=$$( $(CCC) $(C_FLAGS) $(INCLUDE_DIRS) -MM $< ); \
dirName=$$( dirname $< | $(SED) "s/\//\\\\\//g" ); \
dependLine=$$( echo $${dependLine} | $(SED) "s/ $${dirName}\// /g" ); \
oFile=$$( echo $${dependLine} | $(SED) "s/:.*//" ); \
dependencies=$$( echo $${dependLine} | $(SED) "s/.*://" ); \
echo $${oFile} $${oFile%.o}.d: $${dependencies} | $(SED) "s/ \\\//g" > $#
$(UNIQUE_ASSEMBLE_TARGETS): DEP_NAME = $(#:_LIB_NAME=)
$(UNIQUE_ASSEMBLE_TARGETS): MAKE_TARGET = $(if $(filter %_TEST, $(DEP_NAME)), assemble-tests, assemble)
$(UNIQUE_ASSEMBLE_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) $(MAKE_TARGET))
# First, remove the _EXE_NAME attached by EXE_TARGETS, a
$(EXE_TARGETS): DEP_NAME = $(#:_EXE_NAME=)
$(EXE_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) link)
$(CLEAN_TARGETS): DEP_NAME = $(#:_CLEAN=)
$(CLEAN_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) clean)
$(INSTALL_TARGETS): DEP_NAME = $(#:_INSTALL=)
$(INSTALL_TARGETS):
$(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) && $(MAKE) install)
#Local stuff
# The rule to change either a '.c' or a '.m' to a '.o'
#%.o : %.c %.d %.cc %.cpp
.cc.o .cpp.o .c.o:
#echo "Compiling \"$<\""
#$(CCC) -c $(C_FLAGS) $< -o $#
.cc.d .cpp.d .c.d :
#echo "Creating dependency for \"$<\""
# #$(CCC) $(WARNINGS) $(INCLUDE_DIRS) -MM $< -o $#
# This foogly hack because gcc seems to have issues with emitting the correct target/dependency names of
# files in sub-dirs of the current dir (specifically, it doesn't add the sub-dir to the target
# name, and insists on adding the directory to the dependencies) which ends up breaking dependencies...)
#dependLine=$$( $(CCC) $(C_FLAGS) $(INCLUDE_DIRS) -MM $< ); \
dirName=$$( dirname $< | $(SED) "s/\//\\\\\//g" ); \
dependLine=$$( echo $${dependLine} | $(SED) "s/ $${dirName}\// /g" ); \
oFile=$$( echo $${dependLine} | $(SED) "s/:.*//" ); \
dependencies=$$( echo $${dependLine} | $(SED) "s/.*://" ); \
echo $${oFile} $${oFile%.o}.d: $${dependencies} | $(SED) "s/ \\\//g" > $#
$(LOCAL_LIB): compile $(ASSEMBLE_TARGETS)
#echo Assembling $(LOCAL_LIB_NAME)...
#ar rs $(LOCAL_LIB) $(LOCAL_O_FILES)
# Create the executable
$(EXE_NAME): assemble
#echo Linking $(EXE_NAME)...
#$(CCC) -o $(EXE_NAME) $(L_FLAGS)
# Erase all object files, the dependencies file, the core file and the executable, then rebuild everything
LOCAL_CLEAN:
#echo Cleaning $(PROJECT)...
#rm -f $(LOCAL_O_FILES) $(LOCAL_TEST_O_FILES) $(LOCAL_LIB) $(LOCAL_TEST_LIB) $(EXE_NAME) $(TEST_EXE_NAME) $(LOCAL_D_FILES) $(LOCAL_TEST_D_FILES) $(TEST_RUNNER) $(TEST_RUNNER:.o=.d) core*
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
-include $(LOCAL_O_FILES:.o=.d) $(LOCAL_TEST_O_FILES:.o=.d)
endif
The paths to my mpicxx compiler (needed for the cluster, and for those unfamiliar, it wraps gcc) are correct, as evidenced by the fact that it does compile, it just won't link. Similarly, my boost library paths seem functional, the -lboost_mpi flag gets caught properly.
At this point, my question has extended to be for my own education based on how this makefile works/intends to work. Ultimately the entirely obvious/simple command:
mpicxx boosttest.cpp -L ~/boost/stage/lib/ -lboost_mpi -lboost_serialization -o test
however I want to get a proper makefile going as once I get past this test case verifying Boost.MPI's equivalent of a hello world, I'll be moving on to projects involving my full source code, 20+ files with cross dependencies, etc. Any help or intuition would be greatly appreciated.
Based on the suggestion of #Oktalist above, I was able to find something that works, at least for the single-file case, but I can't see why it won't work when I extend this to multiple files. I'm still at a loss why this worked in the past but not now, but perhaps I changed something I wasn't tracking.
The correction is near the end, in this block:
# Create the executable
$(EXE_NAME): assemble
#echo Linking $(EXE_NAME)...
#$(CCC) $(L_FLAGS) $(LOCAL_LIB) -o $(EXE_NAME)