Best practice for building a make file

后端 未结 2 844
失恋的感觉
失恋的感觉 2020-12-03 12:55

Background:

I am relatively new to Make and I started building a makefile for my Othello game I recently built. My current makefile is relatively simple. Yet I am lo

相关标签:
2条回答
  • 2020-12-03 13:24

    For a single folder project I built this Makefile *Note the executable generated has been changed to Game

    all: build archive
    
    build: Game
    
    Game: main.o Myothello.o space.o game.o
        clang++ main.o Myothello.o space.o game.o -o Othello
    
    main.o: main.cc
        clang++ -c main.cc
    
    game.o: game.cc
        clang++ -c game.cc
    
    Myothello.o: Myothello.cc
        clang++ -c Myothello.cc
    
    space.o: space.cc
        clang++ -c space.cc
    
    clean:
        rm -f *.o core *.core
    
    archive: main.cc game.cc Myothello.cc space.cc char.h  colors.h game.h 
    space.h Myothello.h makefile
        tar -cf archive.tar main.cc game.cc Myothello.cc space.cc char.h  
        colors.h game.h space.h Myothello.h makefile
    

    This works assuming all of your files are in the same directory This is where I found my information

    http://www.tutorialspoint.com/makefile/makefile_example.htm

    https://www.tecmint.com/18-tar-command-examples-in-linux/

    https://www.gnu.org/software/make/manual/html_node/Simple-Makefile.html

    ftp://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_toc.html

    0 讨论(0)
  • 2020-12-03 13:32

    Here is an example makefile for you, tested on your github project.

    Features:

    1. Automatic dependency generation.
    2. Automatic rebuild when Makefile is changed.
    3. Debug/release builds in different directories. Debug build is the default, use make BUILD=release for release builds.
    4. Supports gcc and clang. gcc is the default, use make COMPILER=clang for clang.
    5. clean target works by removing the entire build directory.
    6. run target to build and run, e.g. make run_othello.

    Limitations:

    1. Assumes that all source files are in the same directory. In a bigger project there are going to be multiple directories each with multiple build targets (executable, static or shared library). An isomorphic build directory structure is required to support this. Which is totally doable but requires more complexities in example Makefile below, so that it omitted for brevity.

    When archiving you may like to archive only the source files and the makefile. No need to include any build artefacts (like object files, libraries and executables).


    # ==== Begin prologue boilerplate.
    all : # The canonical default target.
    BUILD := debug
    build_dir := ${CURDIR}/${BUILD}
    exes := # Executables to build.
    # ==== End prologue boilerplate.
    
    # ==== Begin define executable othello.
    exes += othello
    objects.othello = main.o game.o Myothello.o space.o
    -include ${objects.othello:%.o=${build_dir}/%.d} # Include auto-generated dependencies.
    # ==== End define executable othello.
    
    # ==== Begin define another executable.
    # ... as for othello
    # ==== End define another executable.
    
    # ==== Begin rest of boilerplate.
    SHELL := /bin/bash
    COMPILER=gcc
    
    CXX.gcc := /bin/g++
    CC.gcc := /bin/gcc
    LD.gcc := /bin/g++
    AR.gcc := /bin/ar
    
    CXX.clang := /bin/clang++
    CC.clang := /bin/clang
    LD.clang := /bin/clang++
    AR.clang := /bin/ar
    
    CXX := ${CXX.${COMPILER}}
    CC := ${CC.${COMPILER}}
    LD := ${LD.${COMPILER}}
    AR := ${AR.${COMPILER}}
    
    CXXFLAGS.gcc.debug := -Og -fstack-protector-all
    CXXFLAGS.gcc.release := -O3 -march=native -DNDEBUG
    CXXFLAGS.gcc := -pthread -std=gnu++14 -march=native -W{all,extra,error} -g -fmessage-length=0 ${CXXFLAGS.gcc.${BUILD}}
    
    CXXFLAGS.clang.debug := -O0 -fstack-protector-all
    CXXFLAGS.clang.release := -O3 -march=native -DNDEBUG
    CXXFLAGS.clang := -pthread -std=gnu++14 -march=native -W{all,extra,error} -g -fmessage-length=0 ${CXXFLAGS.clang.${BUILD}}
    
    CXXFLAGS := ${CXXFLAGS.${COMPILER}}
    CFLAGS := ${CFLAGS.${COMPILER}}
    
    LDFLAGS.debug :=
    LDFLAGS.release :=
    LDFLAGS := -fuse-ld=gold -pthread -g ${LDFLAGS.${BUILD}}
    LDLIBS := -ldl
    
    COMPILE.CXX = ${CXX} -c -o $@ ${CPPFLAGS} -MD -MP ${CXXFLAGS} $(abspath $<)
    PREPROCESS.CXX = ${CXX} -E -o $@ ${CPPFLAGS} ${CXXFLAGS} $(abspath $<)
    COMPILE.C = ${CC} -c -o $@ ${CPPFLAGS} -MD -MP ${CFLAGS} $(abspath $<)
    LINK.EXE = ${LD} -o $@ $(LDFLAGS) $(filter-out Makefile,$^) $(LDLIBS)
    LINK.SO = ${LD} -shared -o $@ $(LDFLAGS) $(filter-out Makefile,$^) $(LDLIBS)
    LINK.A = ${AR} rsc $@ $(filter-out Makefile,$^)
    
    all : ${exes:%=${build_dir}/%} # Build all exectuables.
    
    .SECONDEXPANSION:
    # Build an executable.
    ${exes:%=${build_dir}/%} : ${build_dir}/% : $$(addprefix ${build_dir}/,$${objects.$$*}) Makefile | ${build_dir}
        $(strip ${LINK.EXE})
    
    # Run an executable. E.g. make run_othello
    ${exes:%=run_%} : run_% : ${build_dir}/%
        @echo "---- running $< ----"
        /usr/bin/time --verbose $<
    
    # Create the build directory on demand.
    ${build_dir} :
        mkdir $@
    
    # Compile a C++ source into .o.
    # Most importantly, generate header dependencies.
    ${build_dir}/%.o : %.cc Makefile | ${build_dir}
        $(strip ${COMPILE.CXX})
    
    # Compile a C source into .o.
    # Most importantly, generate header dependencies.
    ${build_dir}/%.o : %.c Makefile | ${build_dir}
        $(strip ${COMPILE.C})
    
    clean :
        rm -rf ${build_dir}
    
    .PHONY : clean all run_%
    
    # ==== End rest of boilerplate.
    
    0 讨论(0)
提交回复
热议问题