Search code examples
cmakefilevscode-debuggerlldb

debugging c code compiled with Makefile using vscode and lldb on linux


I am using vscode on archlinux and I need to debug line by line a C code compiled with a makefile.
I have create a task and a launch json which me allow to examine step by step, but I cannot inspect variable throw debug console or through vscode interface.

This is an extract of Makefile

CFLAGS  = -Wall -Wextra -Wextra -Wswitch-default -Wswitch-unreachable -Wswitch-bool \
          -Wmisleading-indentation -Wnull-dereference -Winit-self -Wstack-protector -Wformat \
          -Wformat-security -Wformat-overflow -Wdouble-promotion -Wunused-parameter -Wunused-const-variable \
          -Wuninitialized -Wpointer-arith -Wincompatible-pointer-types -Wbad-function-cast \
          -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wlong-long -Og -g -O0\
          -Ofast
LDFLAGS = -gdwarf-2 -L/usr/local/lib


.PHONY: clean cleandep mrproper

all: $(EXEC)

myprogram: $(OBJ)
    $(CC) -g  -o $@ $^ $(LDFLAGS) $(LIBS) 

[...]

debug: CFLAGS += -DDEBUG -g
debug: $(EXEC)

Regarding the launch and tasks json, they are the same i used in another file (compiled without makefile), so I am quite sure of them.

Basically, when I use the debug console "print <variable>", <variable> is not defined.
I copied this structure How to "fix" debugger in VScode if you have Makefile project on C++? but it used cppdb, which is not supported in archlinux.

UPDATE my mistake, in main variable are printed, inside function called by the main, I cannot see variable content (undeclared identifier)


Solution

  • I don't know if this is related to your problem, but this makefile is not very well formed. Using target-specific variables like this is not a good idea.

    We will assume (although you didn't provide enough of the makefile to be sure) that the EXEC variable is indeed set to the value myprogram. Then you have this:

    all: myprogram
    
    myprogram: $(OBJ)
            $(CC) -g  -o $@ $^ $(LDFLAGS) $(LIBS) 
    
    debug: CFLAGS += -DDEBUG -g
    debug: myprogram
    

    The problem with this is that if you run make followed by make debug you might think you are building your program with the extra -DDEBUG -g, but you are not.

    When you run make it builds all the object files and executable without the extra -DDEBUG -g. Then when you run make debug it will see that all the targets are up to date already, and it won't rebuild them. That means none of your extra flags have any effect.

    If you change some source files and run make debug, then only those source files that you changed will be recompiled with the extra flags and only those source files will be compiled with debugging.

    Make has no idea what options are being used and it can't tell whether they have changed. It only knows about the modification times of files.

    If you want to use this method of creating debug builds in your makefile, you must remember to do a make clean or equivalent (delete all the build products) every time you switch between running make (without debug) and make debug. Otherwise you'll get a mish-mash of object files built different ways.

    A more reliable, and more common, way to handle this is to write the output files for different types of builds to different directories: so the optimized object files and myprogram binary might go into an opt subdirectory and the debug object files and myprogram binary might go into a debug subdirectory. Then make will understand which files were built with which flags, and they won't get confused.

    Maybe you are already careful to do this clean operation and you just didn't mention it in your question. There is simply not enough detail in your question to know what the problem is. If you really want to know if the compilation is correct the best thing to do is look at the compile lines that make prints out when you run it. Do you see the -DDEBUG -g options in those compile lines? Do you see either no -O option, or else -O0 as the last one? It could be something completely different; for example maybe the rules you are using to compile the code (that you elided with [...]) are not right and are not being used.

    Also just as a note, it's usually safest to put the $(CFLAGS) variable on the link line as well as the compile line; the compiler front-end will ignore compile options when it invokes the linker but the linker wants to know about, for example, the -g option to enable debugging.