0

我对make不是很熟悉;我一直使用和修改这个从另一个项目继承的非常古老的 makefile,并根据需要进行修改。到目前为止,它运行良好,将包含 20-50 个文件的项目编译在一起,即使在子目录中,也能正确确定和构建所有依赖项。

今天我正在运行一个非常简单的测试代码来确定 BOOST.MPI 是否可以在我最近访问的集群上工作。我正在尝试编译一个 1 文件测试用例以确保该库正常工作。这也是我第一次在这个系统上构建和链接来提升。

我在我的用户目录中安装了 boost:~/boost,并且我已经运行了适当的 bjam 以确保 BOOST.MPI 存在。我不相信我的问题出在那儿。但是,正如您稍后会看到的,我必须包含-lboost_mpi-lboost_serialization才能达到我所做的那样。

makefile 似乎可以编译,并且可以很好地组装生成中间 .a 文件。它挂断了链接步骤,出现了一个令人惊讶的错误:

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

我编写的唯一源代码(从Boost.MPI 实现页面复制/粘贴):

升压测试.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;
}

现在是我迷路的部分。这是我修改的makefile。我主要了解它在做什么,它是我见过的唯一一个生成文件(尽管如上所述我对它们不是很有经验)来生成包含所有依赖库列表的 .d 文件。

生成文件:

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

我的 mpicxx 编译器的路径(集群需要,对于那些不熟悉的,它包装 gcc)是正确的,正如它编译的事实所证明的那样,它只是不会链接。同样,我的 boost 库路径似乎可以正常工作, -lboost_mpi 标志被正确捕获。

在这一点上,我的问题已经扩展到基于这个 makefile 如何工作/打算工作的我自己的教育。最终完全明显/简单的命令:

mpicxx boosttest.cpp -L ~/boost/stage/lib/ -lboost_mpi -lboost_serialization -o test

但是,一旦我通过了验证 Boost.MPI 相当于 hello world 的测试用例,我想获得一个正确的 makefile,我将继续进行涉及我的完整源代码、20 多个具有交叉依赖关系的文件等的项目。任何帮助或直觉将不胜感激。

4

1 回答 1

0

根据上面@Oktalist 的建议,我能够找到一些有用的东西,至少对于单文件的情况,但我不明白为什么当我将它扩展到多个文件时它不起作用。我仍然不知道为什么这在过去有效但现在无效,但也许我改变了一些我没有跟踪的东西。

更正接近尾声,在此块中: # 创建可执行文件 $(EXE_NAME): assemble @echo Linking $(EXE_NAME)... @$(CCC) $(L_FLAGS) $(LOCAL_LIB) -o $(EXE_NAME)

于 2012-09-02T00:19:49.677 回答