vscode-makefile-tools/docs/troubleshooting.md

12 KiB

Makefile Tools: Troubleshooting

This document describes reasons and workarounds for errors you might run into when using the Makefile Tools extension.

If you see header squiggles:

  • Verify headers are not missing from the expected location
    • Some headers may be automatically generated by a build, so squiggles are expected on clean repository
  • Verify include paths
    • Check the Makefile Tools output tab or makefile.extensionLog to see which include paths are parsed and sent by Makefile Tools
    • Then check the C/C++ output tab and diagnostics channel to see which include paths are received by the C++ extension

If you see language squiggles:

  • Verify (with makefile.loggingLevel set to "Verbose" or "Debug") in the output channel or in the makefile.extensionLog what are the compiler switches that Makefile Tools parses from the original compiler command line. These need to match the compiler switches from C/C++ output and diagnostic channels, with C_Cpp.loggingLevel set to "Debug"

Various issues may happen if the project:

  • Uses parallel execution (interleaved output may cause wrong current paths to be computed, resulting in IntelliSense missing for files registered under the wrong path)
    • Experiments with -j 1, --output-sync=recurse (and ignore the timeout popup) don't always work
  • Invokes recursive make calls (paths may be incorrect)
  • Silences the output via various directives (so that V=1 doesn't display commands, or directories operations are hidden, etc.)
  • Executes terminal commands embedded in the compiler/linker commands via backtick (see mono repository: cordxtra.c). Example: CXXFLAGS += `sdl2-config --cflags`
    • The extension will invoke on the fly these commands to extract their output: https://github.com/microsoft/vscode-makefile-tools/issues/81

    • Until the above work item is implemented, the users need to apply some workarounds in their repositories: the backtick constructs should be replaced with the shell command syntax like:

      CXXFLAGS += $(shell sdl2-config –cflags)

    • If the above workaround is missing, the extension is still able to handle the following most commonly found backtick pattern:

      • `test –f 'cord/cordxtra.c' || echo './'`cord/cordxtra.c

makefile.ignoreDirectoryCommands behavior:

  • Defaults to True (when we look only at what make prints from the -C argument or when make knows it changes directory)
  • True will miss any target-specific defined operations like cd, pushd, popd and the extension may calculate a wrong current path, which can result in can result in IntelliSense information being associated to a file URL that does not point to the original source file.
    • This is rare, which is why True is default.

Dryrun behavior:

  • If repository is clean (no previous build was run, or a clean was run before configure):
    • dryrun includes all source files even if --always-make is missing
    • automatically generated headers may be missing, causing squiggles
    • a dryrun after clean may not be able to provide IntelliSense for those source files that are discoverable by the build only after other portions of the project were built for real
  • If a build was done before configure:
    • dryrun may provide data only for out-of-date files, unless --always-make is used
    • Headers and other resources are present
  • A dryrun on clean, a dryrun after a build, and a real build can all produce a different set of source files for IntelliSense and different build/launch targets. Each operation, in the context of how each code base is setup, produces a different build log (even in the Terminal, outside of Makefile Tools)

--always-make behavior:

  • If present, ensures all data is available but may cause unwanted targets to be run. This might result in losing a previously configured state (linux kernel) or an infinite dryrun (swig on GitHub)
    • Special note for swig: the configure target is written in the Makefile in such a way that it always runs again if it fails, which it does when run via --always-make (versus via ./configure in terminal). In this case we don't even get a timeout popup becaused the log keeps writing new paragraphs indefinitely.
  • If absent, the dryrun can't get complete info without workarounds like crafting a special target to 'touch' (mark as out of date) the right things and running this special target before configure. But this would cause an unwanted rebuild of up-to-date sources when a real build is done.

If a dryrun is too long (mono, curl, zgs....):

  • Try removing –always-make and save a dryrun log after a clean (so that all files are seen without –aways-make)
  • Point makefile.buildLog to a build log instead of using dryrun
    • Example where a build log is needed: when make invokes libtool, because the output from libtool (which is run for real during a build) is richer than the output of make dryrun which is just printing the command of how libtool is invoked.
    • Known issue: even if a build log is given to avoid a make run, sometimes the make invocation for targets (which currently happens live, doesn't read from a log) is still very long (example: curl repository). Tracked by https://github.com/microsoft/vscode-makefile-tools/issues/93.

If the repository needs any special commands before make is successful:

  • Write any commands (./configure, ./bootstrap, etc...) in a script and point to it via makefile.preconfigureScript
    • In the script, we recommend you concatenate all commands into one line, separated by && (for better return code analysis)
  • Any arguments that you'd like to pass to the preConfigureScript should be set via makefile.preConfigureArgs
  • From the Command Pallette, run the Makefile: Pre-Configure command once before configuring your project.
  • If you need this every time, set makefile.alwaysPreConfigure to true

If the repository or build needs any special commands to clean up after a build:

  • Write any commands in a script and point it via makefile.postConfigureScript
    • In the script, we recommend you concatentate all commands into one line, seperated by && (for better return code analysis)
  • Any arguments that you'd like to pass to the postConfigureScript should be set via makefile.postConfigureArgs
  • From the Command Pallette, run the Makefile: Post-Configure command once after configuring your project.
  • If you need this every time, set makefile.alwaysPostConfigure to true

If there is no Makefile in the root:

  • Point makefile.makefilePath or makefile.configurations.makefilePath to your Makefile (if you use the "-f" make switch). If you prefer to use the switch "-C" you can point makefile.makeDirectory or makefile.configurations.makeDirectory to the folder containing your makefile.
  • Manually activate the extension by either reloading the window or running any Makefile Tools command (like Configure) from the Command Palette

Launch targets missing:

  • If there are launch targets that you expected to be found but are missing, try building first.
    • Before building, the extension only sees the output file of a link command and it will create a launch target with running that output file from the location where it is built and without passing any arguments. The output file does not have to exist in order to be included in launch targets list.
    • But if you expected to see a particular binary being run with some arguments, then the makefile must contain a target which invokes that binary and the binary should be present at the build location
  • it's possible to include in the list libraries/objects instead of executables, when there is no obvious switch that indicates that the linker is not creating an executable. Workitem https://github.com/microsoft/vscode-makefile-tools/issues/94 will make sure we correctly identify only executable launch targets.

If you see a squiggle at the beginning of a source file with the error message "command-line error: language modes specified are incompatible":

  • That is usually a symptom of the file being missing from the dryrun output, the extension finds no compilation command to parse and does not have any information to send to CppTools, in which case the C++ extension defaults to tag parser.
  • The same root cause may also manifest as headers and defines squiggles (instead of incompatible language modes) throughout a source file whose URL is not associated with any information sent to CppTools
  • Both symptoms are accompanied by the following message in the output channel: "Configuration for file was not found. CppTools will set a default configuration."

If your Build targets list is too long:

  • Use makefile.phonyOnlyTargets to filter out targets that the Makefile explicitly defines as Phony

Watch out for tricky lines in dryrun/build logs that may cause crashes or infinite loops when the extension parses content:

  • many dashes in a row (---------------------) causes infinite recursion according to regexp101.com
  • LK repository dryrun has 6000 char lines and many such lines in a row, each of them is very slow (takes hours)
  • Tip: disable MAKECONFIGHEADER in make/macros.mk, to avoid the enormous echo commands from being printed
    • This can be done under a make flag that can be tied to makefile.configurations.makeArgs to only avoid the echos when in dryrun mode

How to use Makefile Tools knowledge in launch.json (expansion of variables and commands is not yet supported in the Makefile Tools settings of settings.json):

  • "cwd": "${command:makefile.getLaunchTargetDirectory}",

  • "name": "Launch Program Name",

  • "program": "${command:makefile.getLaunchTargetPath}",
    or
    "program": "{command:makefile.getLaunchTargetDirectory}/{command:makefile.getLaunchTargetFileName}",

  • "args": ["${command:makefile.getLaunchTargetArgs}"],
    or
    "args": ["${command:makefile.getLaunchTargetArgsConcat}"]

Build before launch:

  • buildBeforeLaunch setting controls whether a build of the current target should run before debug/run.
  • When using debug/run via launch.json (and not the makefile commands for debug/run), the correct way to trigger a build is by using the preLaunchTask keyword. This doesn't work now and we plan to implement tasks support very soon: https://github.com/microsoft/vscode-makefile-tools/issues/101.
  • Until we implement tasks support, we added 2 commands that are triggering a build:
    • ${command: makefile.launchTargetPah}, which returns the same path as getLaunchTargetPah
    • ${command: makefile.launchTargetFileName}, which returns the same file name as getLaunchTargetFileName
  • Throughout one launch.json configuration, only one of these two commands should be invoked and only once, otherwise the launch will trigger more than one build. The extension can't mitigate this because it doesn't know how many times VSCode will call into it. If commands for launch target path or file name are needed more than once, invoke once without the get prefix and the rest only with the get prefix, so that the project builds only one time.

Capturing build errors/warnings in the "Problems" tab:

  • By default, the extension should automatically detect gcc and msvc style of error reporting. If your build tools report their warnings/errors differently, you can contact us to implement a custom problem matcher or, if another extension already implements such problem matcher you can reference it with an additional entry in the makefile.configurations[].problemMatchers array.
  • If your makefile calls MAKE pointing to other CWDs with -C and your compilation tools are logging source files with relative paths (to the folder of the current make invocation), the problem matcher may not be able to correctly identify the source files because our problem matchers calculate relative paths to the workspace folder or to the -C switches that are passed originally to the entry point makefile. We will address this problme in future (https://github.com/microsoft/vscode-makefile-tools/issues/257) and until then you can ensure your project changes folder only once or loggs full paths source files.