1
\$\begingroup\$

Following this question on meta TL;DR Not sure whether this question is too general...

The idea is to have a universal (ish) makefile, that can be dropped into any C++ Sublime Text Project and it work with any combination of the GMP,SDL2 and pthread libraries. There is then a choice of how I compile/link through the Sublime Text 3 build system.

(Unfortunately I can't show you the Sublime build api, because when I try a screen shot the relavent window automatically closes.)

In essence ST3 (Sublime Text 3) is calling the makefile 'build_MUTAG_Dbug.mk' with various different flags passed to it eg GMP=true PED=true THREAD=true and depending on these values, that dictates the various libraries the project will be compiled/linked with.

I am going to put my questions in the comments of the makefile so that questions have context.

(As per) I'm self learning.

The Sublime Text 3 build system looks like this. The actual JSON file is much bigger, as there are options to just build one source file (with all lib combinations), as well as the whole project:

{
  "cmd" : ["make default --file=build_MUTAG_Dbug.mk -B TARGET=\"$file_base_name\""],
  "selector" : "source.c",
  "shell": true,
  "file_regex": "^(.+):([0-9]*):([0-9]*):(.*)$",
  "working_dir": "${file_path}",
  "syntax": "Packages/Makefile/Make Output.sublime-syntax",
  "variants":
  [
    {
      "name": "Clang++ GMP, SDL2 & thread",
      "shell_cmd": "make sdl2 --file=build_MUTAG_Dbug.mk -B DEBUGFLAG=-DDEBUG GMP=true THREAD=true TARGET=\"$file_base_name\""
    },
    {
      "name": "Clang++ Pedantic GMP, SDL2 & thread",
      "shell_cmd": "make sdl2 --file=build_MUTAG_Dbug.mk -B DEBUGFLAG=-DDEBUG GMP=true PED=true THREAD=true TARGET=\"$file_base_name\""
    },
    {
      "name": "Clang++ GMP, SDL2 & thread NOT everything Only CHANGED",
      "shell_cmd": "make sdl2 --file=build_MUTAG_Dbug.mk DEBUGFLAG=-DDEBUG GMP=true THREAD=true TARGET=\"$file_base_name\""
    },
    {
      "name": "G++ SDL2",
      "shell_cmd": "make sdl2 --file=build_MUTAG_Dbug.mk -B CC=g++-7 DEBUGFLAG=-DDEBUG TARGET=\"$file_base_name\""
    },
  ]
}

Here's the makefile build_MUTAG_Dbug.mk ,directory structure (& code)


# Directory structure:
# Main Project/FileHandling
# Main Project/Graphics
# Main Project/Ancillaries

# The final app MUTAG has some of the larger header and source files   # in the same directory   
# and then all the ancillary header and sources are distributed    
# according to function
# in the other directories (See before makefile code).

# Is this the correct way to use VPATH ?
# Is this generally the right way of writing a make file to compile a project with a directory structure such as this ?
# Would there be some command-line magic to get a list of all directories using a bash
# script say and then 'feeding' that to VPATH, or does the directory structure always
# have to be hard coded into the makfile ?

VPATH = FileHandling:Graphics:Ancillaries

# These are for string substitutions later
DIR1 = FileHandling/
DIR2 = Graphics/
DIR3 = Ancillaries/


CC = clang++-3.8
GMP = false
THREAD = false
PED = false
SDL2FLAGS = -lSDL2 -lSDL2_image -lSDL2_ttf
GMPFLAGS =  -lgmp -lgmpxx
THREADFLAGS = -pthread
LDTHEADFLAGS = -lpthread

PEDFLAGS = -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy\
-Wdisabled-optimization -Wformat=2 -Winit-self  -Wmissing-declarations\
-Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls\
-Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef\
-Werror -Wunused -Wextra  -Wunused-but-set-parameter -fdiagnostics-show-option

DEBUGFLAG =
SANITIZEFLAGS =  -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
LDLIBSXTRA = -lstdc++fs

# Note to self:LDFLAGs for -L rather than -l LDFLAGS = ...
# lc++ for libstd clang gdb symbols

LDLIBS = -lc++ -lm -lgcc_s -lgcc -lc

# Sorting the different flags out for different compilers and modes
# stdlib=libc++ if for gdb to "decode" std::string

ifeq ($(CC),g++-7)
  CXXFLAGS = -std=c++17 -w -O0 -ggdb
  LDLIBS += $(LDLIBSXTRA)
  sdl2:LDLIBS += $(SDL2FLAGS)
else
  CXXFLAGS = -std=c++14 -stdlib=libc++ -w -O0 -ggdb3
  sdl2:LDLIBS += $(SDL2FLAGS)
endif


# I'm sure using the 'sdl2' flag like this is wrong (it does however work).
# The first flag after make is for all/clean etc. Am I correct in
# this assumption?
# To do it properly I'd have to have another flag say SDL and check 
# whether it was true/false like the other flags (PED,GMP etc) ?


# Resolving flags passed to makefile to determine which libraries are
# used during compile and link

ifeq ($(THREAD),true)
  CXXFLAGS += $(THREADFLAGS)
  LDLIBS += $(LDTHEADFLAGS)
endif

ifeq ($(GMP),true)
  LDLIBS += $(GMPFLAGS)
endif

ifeq ($(PED),true)
  CXXFLAGS += $(PEDFLAGS)
endif

# Am I using the '-I' flag correctly? Again would there be someway  
# of automating this so that it would work for any directory
# structure ?

CPPFLAGS = -I"/home/elitebook/Desktop/Big Mandlebrot/Final Project/FileHandling/"\
-I"/home/elitebook/Desktop/Big Mandlebrot/Final Project/Graphics/"\
-I"/home/elitebook/Desktop/Big Mandlebrot/Final Project"\
-I"/home/elitebook/Desktop/Big Mandlebrot/Final Project/Ancillaries/"


CXXFLAGS += $(DEBUGFLAG)

SRCS4 := $(wildcard $(DIR3)*.cpp)
SRCS3 := $(wildcard $(DIR2)*.cpp)
SRCS2 := $(wildcard $(DIR1)*.cpp)
SRCS1 := $(wildcard *.cpp)

# So that sources are *.cpp /FileHandling/*.cpp & /Graphics/*.cpp
SRCS = $(SRCS1) $(SRCS2) $(SRCS3) $(SRCS4)

# However all the object files are in the same dir as the linker so have
# to remove FileHandling/ and Graphics/ from the source files to get correct
# object file names , ie one without directory precursors

OBJS := $(patsubst %.cpp,%.o,$(SRCS))
OBJS := $(patsubst $(DIR1)%,%,$(OBJS))
OBJS := $(patsubst $(DIR2)%,%,$(OBJS))
OBJS := $(patsubst $(DIR3)%,%,$(OBJS))

# check srcs and objs are ok...
$(info SRCS are $(SRCS))
$(info OBJS are $(OBJS))

sdl2: $(TARGET)
default:$(TARGET)

%.o: %.cpp
    $(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< ; pwd

$(TARGET): $(OBJS)
    g++-7 $^ $(LDLIBS) -o $@

Finally I've left the object files in the directory, to make sure they've been compiled and I can check the time stamp.
Traditionally they're removed ?
And there should be a .PHONEY which I'm not sure about as all the above works?

Edit: I was having some comment formatting issues, which I've changed and are detailed in the comments

\$\endgroup\$
4
  • \$\begingroup\$ I'm not sure what's going on with the last set of comments, two or more spaces aren't producing a newline, no about of fiddling is getting it right. Mini markdown in comments ? \$\endgroup\$
    – Lozminda
    Apr 13, 2022 at 12:04
  • \$\begingroup\$ Why would two spaces in a preformatted code block break the line? Markdown is explicitly disabled inside code blocks (otherwise chaos would ensue). But even outside code blocks, two spaces do not create a line break in Markdown; only two spaces followed by a newline do. \$\endgroup\$ Apr 13, 2022 at 13:53
  • \$\begingroup\$ @KonradRudolph stackoverflow.com/questions/33191744/… The reply with 138 votes says To force a line return, place two empty spaces at the end of a line. In fairness other parts say as you, I must have misread. There's a few posts about this issue dotted around. \$\endgroup\$
    – Lozminda
    Apr 13, 2022 at 22:37
  • \$\begingroup\$ Right, the bit that you missed in that answer is “at the end of the line” — and what that answer misses is the fact that this only works in regular text, not in code blocks. Inside code blocks, a regular line break works. (Furthermore, forced line breaks in regular text should almost never be used! They have no place in conventional typography, outside of poems. Use paragraph breaks instead.) \$\endgroup\$ Apr 14, 2022 at 7:56

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.