3

all. Some of you who have helped me in the past might already know that my code is pretty messed up because of all of my #include statements including .cpp files. My question is, how am I supposed to correctly implement the make file to link everything together correctly?

What I currently have:

CC = g++

# Compiler flags:
# -g     - debugging info.
# -Wall  - used to turn on most compiler warnings.
CFLAGS = -g -Wall

# The build target
TARGET = icbins

# To bring exe up to date:

$(TARGET): main.o m1/cell.o m1/abstractions.o m1/expression.o m1/arithmetic.o m1/logic.o m1/cell.o m1/grid.o parsing/token.o parsing/lexer.o parsing/parser.o interface/icbins.o
    $(CC) $(CFLAGS) -o $(TARGET) main.o m1/cell.o m1/abstractions.o m1/expression.o m1/arithmetic.o m1/logic.o m1/cell.o m1/grid.o parsing/token.o -lncurses

main.o: main.cpp
    $(CC) $(CFLAGS) -c main.cpp

clean:
            $(RM) $(TARGET)

Yeeeah. not the best. I don't really know what I am doing with this, so any help is appreciated. My current folder structure:

project -
     main.cpp
     
     interface -
          icbins.cpp
     m1-
          abstractions.cpp
          arithmetic.cpp
          cell.cpp 
          expression.cpp 
          grid.cpp 
          logic.cpp
     parsing-
          lexer.cpp 
          parser.cpp 
          token.cpp 
     types.h

The main.cpp is supposed to be the driver and ./icbins is the executable file.

My current makefile "works", but not well...

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 1
    what's wrong with your make file? – Alan Birtles Apr 18 '23 at 17:57
  • 1
    One recommendation: Look into Cmake. Let it do the makefile-building scut work. – user4581301 Apr 18 '23 at 18:00
  • Here is a very simple example with C files, easily updated to c++, that is answering a completely different question: https://stackoverflow.com/a/48818713/4581301 – user4581301 Apr 18 '23 at 18:04
  • Here's an even better example: https://stackoverflow.com/a/4349717/4581301 Note how it's using arcane sigils to avoid repeating the names of the dependencies over and over. It sort-of covers what those sigils mean, but it's probably better if you look them up on in dedicated documentation. – user4581301 Apr 18 '23 at 18:06
  • This and its top-voted answer are also good reading: https://stackoverflow.com/q/43778870/4581301 – user4581301 Apr 18 '23 at 18:10
  • 1
    One thing: Remove `CC = g++` and replace `$(CC)` (which is for the C compiler) in the makefile with `$(CXX)` (the default C++ compiler). Unrelated: Is the `main.o` rule really needed? It seems you already use the default rule for building object files so why not `main.o`? – Ted Lyngmo Apr 18 '23 at 18:18
  • And where are your header files? – Ted Lyngmo Apr 18 '23 at 18:20
  • i dont have header files. I think that is part of the issue. what should I use them for? – Joshua Morris Apr 18 '23 at 18:38
  • If i have main.cpp and test.cpp and foo() is in test, how do I link the two? In other words, how do I compile so that the methods in test are usable in main? – Joshua Morris Apr 18 '23 at 19:13
  • 1
    That's what the header file is for. Declare the functions in the header, implement them in the cpp file. Include the header in the cpp file that needs the function. Link the two files together. [Some important reading](https://stackoverflow.com/q/6264249/4581301). [More important reading](https://learn.microsoft.com/en-us/cpp/cpp/header-files-cpp?view=msvc-170). – user4581301 Apr 18 '23 at 19:25
  • what am I supposed to do if many of my .cpp files reimplement the same methods? for example, every abstraction in abstraction.cpp is a subtype of expression and all have their own implementation of the evaluate in expression.cpp. maybe have an expression.h that defines the method to start out with? – Joshua Morris Apr 18 '23 at 19:30
  • 1
    Sounds as though you are expected to use overloading or inheritance, btu that is better dealt with in a new question. Research the topic carefully before asking it, though, because loosely worded it will attract down-and-close-votes faster than good answers. – user4581301 Apr 18 '23 at 19:49
  • Different namespaces can provide functions / methods with the same signature. These are nevertheless different functions. The same namespace or different ones can provide functions / methods with the same name but sufficiently different parameter types, and possibly different return types. These also are different functions. But one namespace cannot contain multiple functions / methods with the same name and parameter types. If that's what you mean by different source files providing "the same function", then you're going to need to fix that. – John Bollinger Apr 18 '23 at 20:45
  • @JohnBollinger kind of, Expression.cpp is an abstract class and has an incomplete method, evaluate. any object that is the Expression subtype has to implement its own evaluate. – Joshua Morris Apr 19 '23 at 14:40
  • @JoshuaMorris, methods of different classes are absolutely different functions, all other considerations notwithstanding, including inheritance. This falls into the "different namespaces" category. – John Bollinger Apr 19 '23 at 15:27

1 Answers1

1

Some of you who have helped me in the past might already know that my code is pretty messed up because of all of my #include statements including .cpp files. My question is, how am I supposed to correctly implement the make file to link everything together correctly?

Linking is not really the issue. Your code structure with all the .cpp #includes is. There is good reason for the conventions that have grown up around headers and use of #include.

But perhaps the issue is not so much the includes as understanding what a header is. In particular, I wonder whether some or all of your .cpp files are really misnamed headers. class definitions go in headers, whereas non-inline function definitions and external object definitions go in .cpp files. Any .cpp files that don't contain anything from the latter categories are really headers, and should be named as such (and should have appropriate multiple-inclusion guards).

Anyway, to link everything together, you need to find a set of object files that collectively define all the methods and objects required by the program, exactly once each. Those, and only those, are the objects you link. In fact, those are the only ones you even need to build.

If you don't want to change your code, then you can try choosing the appropriate set of objects this way:

  • Start with one object X.o for each X.cpp source file
  • Look at all the #include directives in your sources. For every Y.cpp file that is #included by another .cpp file, remove Y.o from the set of objects to build or link.

It may be that main.o is the only object left, which would be fine, but if no objects remain then you need to restructure your code. And if you (still) get multiple definition errors when you try to link, then again, you need to restructure your code.

Supposing that you can use built-in rules for compiling the object files, as the code in the question implies, the resulting makefile would look something like this:

CXXFLAGS = -g -Wall

TARGET = icbins
TARGET_OBJS = main.o other/foo.o other2/bar.o ...

$(TARGET): $(TARGET_OBJS)
        $(CXX) $(CXXFLAGS) -o $(TARGET) $^ -lncurses

clean:
        rm -f $(TARGET) $(TARGET_OBJS)

.PHONY: clean
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • That should work. Only issue is, will changes in files only be compiled when main is updated? – Joshua Morris Apr 19 '23 at 19:37
  • @JoshuaMorris, with that particular makefile, changes to the source files corresponding directly to object files designated in `TARGET_OBJS` will make `icbins` out of date. Changes to other sources will not. This is effectively the same issue as with headers: you need to add rules (perhaps prerequisite-only rules) to express the `TARGET_OBJS` objects' dependencies on other sources. – John Bollinger Apr 19 '23 at 19:41