Note that there are some explanatory texts on larger screens.

plurals
  1. POundefined reference to `main' with makefile on linux, with boost and mpi
    primarykey
    data
    text
    <p>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.</p> <p>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.</p> <p>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 <strong>-lboost_mpi</strong> and <strong>-lboost_serialization</strong> to get as far as I did.</p> <p>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:</p> <pre><code>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 </code></pre> <p>The only source code I've written (copy/pasted right out of the <a href="http://www.boost.org/doc/libs/1_51_0/doc/html/mpi/getting_started.html#mpi.config" rel="nofollow">Boost.MPI implementation page</a>):</p> <p><strong>boosttest.cpp:</strong></p> <pre><code>#include &lt;boost/mpi/environment.hpp&gt; #include &lt;boost/mpi/communicator.hpp&gt; #include &lt;iostream&gt; int main(int argc, char* argv[]) { boost::mpi::environment env(argc, argv); boost::mpi::communicator world; std::cout &lt;&lt; "I am process " &lt;&lt; world.rank() &lt;&lt; " of " &lt;&lt; world.size()&lt;&lt; "." &lt;&lt; std::endl; return 0; } </code></pre> <p>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.</p> <p><strong>Makefile:</strong> </p> <pre><code>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 &lt;srcdir&gt;" 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) &amp;&amp; $(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) &amp;&amp; $(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) &amp;&amp; $(MAKE) link) $(CLEAN_TARGETS): DEP_NAME = $(@:_CLEAN=) $(CLEAN_TARGETS): $(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) &amp;&amp; $(MAKE) clean) $(INSTALL_TARGETS): DEP_NAME = $(@:_INSTALL=) $(INSTALL_TARGETS): $(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) &amp;&amp; $(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 \"$&lt;\"" @$(CCC) -c $(C_FLAGS) $&lt; -o $@ .cc.d .cpp.d .c.d : @echo "Creating dependency for \"$&lt;\"" # @$(CCC) $(WARNINGS) $(INCLUDE_DIRS) -MM $&lt; -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 $&lt; ); \ dirName=$$( dirname $&lt; | $(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" &gt; $@ $(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) &amp;&amp; $(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) &amp;&amp; $(MAKE) link) $(CLEAN_TARGETS): DEP_NAME = $(@:_CLEAN=) $(CLEAN_TARGETS): $(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) &amp;&amp; $(MAKE) clean) $(INSTALL_TARGETS): DEP_NAME = $(@:_INSTALL=) $(INSTALL_TARGETS): $(if $(findstring $(DEP_NAME), $(PROJECTS)),,cd $($(DEP_NAME)_DIR) &amp;&amp; $(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 \"$&lt;\"" @$(CCC) -c $(C_FLAGS) $&lt; -o $@ .cc.d .cpp.d .c.d : @echo "Creating dependency for \"$&lt;\"" # @$(CCC) $(WARNINGS) $(INCLUDE_DIRS) -MM $&lt; -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 $&lt; ); \ dirName=$$( dirname $&lt; | $(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" &gt; $@ $(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 </code></pre> <p>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.</p> <p>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:</p> <pre><code>mpicxx boosttest.cpp -L ~/boost/stage/lib/ -lboost_mpi -lboost_serialization -o test </code></pre> <p>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.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload