Search code examples
c++visual-studio-codefftw

How to include compiler flags in Visual Studio Code?


I have a program that I am trying to run in the Visual Studio Code debugger that uses fftw functions. It compiles with the command

g++ dimer.cpp -std=c++11 -lfftw3 

on the terminal on my computer without complaining about undefined references. However, after generating a launch.json file, my program complains about fftw library functions and about the -std=c++14 compiler flag.

I believe that it needs just the extra flags of -std=c++11 and -lfftw3 for the debugger in Visual Studio Code to work. I am using Microsoft's C/C++ extension and the Code Runner extension.

I am trying to transform a Mathematica document of code into c++.

Below are the errors I get from the output.

Executing task: /usr/bin/g++ -g /home/msammartino/Documents/twochain/dimer.cpp -o /home/msammartino/Documents/twochain/dimer <

In file included from /usr/include/armadillo:54:0,
             from /home/msammartino/Documents/twochain/dimer.cpp:6:
/usr/include/armadillo_bits/compiler_setup.hpp:530:108: note: #pragma message: NOTE: suggest to enable C++14 mode for faster code; add -std=c++14 to compiler flags
 #pragma message ("NOTE: suggest to enable C++14 mode for faster code; add -std=c++14 to compiler flags")
                                                                                                        ^
/tmp/ccgb7Xsv.o: In function `r2r_dsine_fftw_forward_dimer(int, double*, double*, Eigen::Matrix<double, 2, 2, 0, 2, 2> (&) [2048], Eigen::Matrix<double, 2, 2, 0, 2, 2> (&) [2048])':
/home/msammartino/Documents/twochain/dimer.cpp:99: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:100: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:101: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:102: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:103: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:104: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:105: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:106: undefined reference to `fftw_execute'
/tmp/ccgb7Xsv.o: In function `r2r_dsine_fftw_backward_dimer(int, double*, double*, Eigen::Matrix<double, 2, 2, 0, 2, 2> (&) [2048], Eigen::Matrix<double, 2, 2, 0, 2, 2> (&) [2048])':
/home/msammartino/Documents/twochain/dimer.cpp:166: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:167: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:168: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:169: undefined reference to `fftw_plan_r2r_1d'
/home/msammartino/Documents/twochain/dimer.cpp:170: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:171: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:172: undefined reference to `fftw_execute'
/home/msammartino/Documents/twochain/dimer.cpp:173: undefined reference to `fftw_execute'
collect2: error: ld returned 1 exit status
The terminal process terminated with exit code: 1

Terminal will be reused by tasks, press any key to close it.

Please let me know about any problems with the way I have asked this question.


Solution

  • The easy option is to pass them as args in your tasks.json configuration:

    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "build-all",
          "type": "shell",
          "args": [
              "-std=c++11",
              "-lfftw3",
              "-L",
              "/path/to/libs",
              "/path/to/file.cpp"
          ],
          "command": "g++",
        }
      ]
    }
    

    The more maintainable, shareable option is to create a Makefile and set them all there:

    # Specify compiler to be used
    CXX = g++
    CXXFLAGS += -g -std=c++11 -fPIC -march=x86-64
    
    # Specify paths to headers
    INCLUDES += -I include
    
    # Specify paths to the libraries
    LDFLAGS  += -L /path/to/libs
    
    # Specify the link libraries
    LLIBS    += -lfftw3
    
    # ... add other configs ...
    
    $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(OBJ_DIR)
        $(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
    
    $(OBJ_DIR)/$(PROGRAM): $(OBJS)
        $(CXX) $(LDFLAGS) $^ $(LLIBS) -o $@
    

    Then in your task configuration, just call make:

    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "build-all",
          "type": "shell",
          "options": {
              "cwd": "${workspaceFolder}",
              "env": {
                ...
              }
          },
          "command": "make -f Makefile.x86_64",
        }
      ]
    }
    

    If you have env-dependent paths, you can specify a variable in your Makefile (ex. MY_LIBS) and then set them in the env block of the task configuration (ex. "MY_LIBS": "/path/to/libs").

    The advantage of the Makefile option is that:

    • People who don't use VS Code can still compile your code (from console or another IDE).
    • If you are using a CI/CD pipeline, you don't need a separate configuration. You can use the same Makefile to build locally with VS Code and to build with CI/CD.
    • You can commit the Makefile to a repository, and then just use environment variables in your local tasks.json configuration to specify env-specific settings.