logo

VSCodium/VSCode On Linux

Posted on: 2023-09-15

VSCodium is VSCode with the Microsoft telemetry removed. It appears that it is possible to use the C/C++ extension on it, but doing do requires downloading the ".vsix" and installing manually. The extension doesn't appear in the extensions list in vscodium. To do this you can download the ".vsix" from the github repository. Then click the bottom left "settings" cog -> extensions, and then click the "...". You should find a "Install from VSIX..." option.

In this discussion I will use VSCode and VSCodium to mean the same thing. Visual Studio means the regular microsoft Visual Studio IDE.

Conclusion Summary

I haven't been using this setup too long and am still mostly trying to feel out the limits. With more real work it will be clearer how practical this really is. Right here right now it seems a plausible way to develop. Debugging has significant rough edges remaining, so that is my greatest concern.

Pros:

Cons:

Debugging

In the "debug console" you can do GDB debugging commands if you prefix with "-exec".

Natvis

It seems as if all you need is something like, in the "launch.json" in the configuration section. You can't set it in launch section in general.

{
  "visualizerFile": "${workspaceFolder}/path/to/file.natvis",
  "showDisplayString": true,
}

VSCode does support multiple visualization files. The paths can just be placed in an array for visualizerFile.

I also regularly see "Explicit refresh required for visualized expressions", it's not entirely clear why or what that means.

Issues

Natvis Format Specifiers

In VSCode format specifiers largely don't work. In particular the array length or array usage with DisplayString don't work.

Links about Natvis format specifiers

In the watch window using ,N where N is an integer does work and is pretty useful.

Include Problem

For my project, I'm using a makefile to build, and then testing with GDB with the C/C++ extension. This introduced a problem where Intellisense was unable to find my includes. The problem is, around the configurationProvider setting. For me this was in "settings.json", but could be in "c_cpp_properties.json". When I commented the option out the include path, was correctly picked up from the includePath setting.

// We comment out this line, because it overrides the includes
//"C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools",

Then the includes can be set in "settings.json"

"C_Cpp.default.includePath": [ "path" ]

Works correctly.

Sharing Configuration Settings

There is also a description of env support. In general I couldn't get this to work as I hoped.

Call Native Functions

Natvis with GDB is more restricted in most ways than on Visual Studio. The one nice addition is that it's okay to call into native functions. This is a very powerful feature, and can be used as a kind of "escape hatch" to fix some of the other problems. It's not without problems though, some described elsewhere. One issue is that in general you can't use it for a templated type, because it would require all instanciations that you want to use to exist in the binary for the call to work.

What is a little awkward is the difficulty of knowing if say a SubString is uninitialized, and so could have a string that produces a crash. This isn't theoretical, and the problem occurred when debugging some simple code. As a workaround this, you could make types initialize to on certain builds such as debug builds.

It's not entirely clear what the constraints are around calling a function that returns a char*.

The most conservative thing to do would be to make calling the function thread safe, and never release the memory.

In practice it seems it's acceptable to just assume always being called from one thread, and the pointer only needs to stay in scope until another call to the function. Time will tell if those assumptions are appropriate. Another consideration is what functionality to use to implement these conversions? We probably don't want to call into normal client/library code as that could make debugging that code very confusing. So it's probably best to use cstdlib functionality and make the implementation as simple as possible.

This functionality would only be required when using GDB (and LLDB perhaps) and so would lead to a splitting out natvis functionality that is specific to a target.

To work around the uninitialized issue, I wrote a function that used mincore to detect if things look reasonable. It's not quite right because if memory is paged out, mincore returns that it's not available. For my purposes though it seems to work well enough.

Care is needed to isolate code called from the debugger such that it is not part of the code to be debugged. Which might mean reimplementing some functionality, and only calling only into standard library functions. This is desirable so as a breakpoint, doesn't get hit when the debugger calls into a native function.

Native Symbols

This is an issue that happens with Native Function Calls as well as with types such as enums. By default when a project links symbols that are not used are not included in the final binary. It seems that symbols from object files from the building project do largely have their symbols intact. Symbols from a library are generally stripped. Since the GDB native debugging functions aren't going to be called from regular code (by design), they are typically stripped. To work around this I added a function to libraries that "registered" these symbols. This was achieved by returning an array of function pointers.

There is a similar problem around enums. If an enum type isn't explicitly used it appears it can be stripped. This can be worked around by adding some "dummy" code that is executed that does reference the type. The enum issue is actually quite important because it is typical in my natvis file to use enum values in conditions to detect different types. When the enum isn't found, the natvis visualization fails to execute.

No Quick Watch

There isn't a quick watch option in VSCode like there is in Visual Studio. With quick watch you can right mouse button over a variable and see it's contents. In VSCode I don't see this option. What you can do is use the watch window. Add the variable and then edit it. That's not quite the same thing, as you have to cut and paste/type in the variable, but isn't too problematic.

Once something is in the watch window it can be clicked and edited fairly quickly. So whilst a bit clunky it is at least workable.

There is also the option to use the GDB debug window. This ends up typing something like

-exec print some-expression

With this feature it is also possible to use GDBs formatting features which might work for some scenarios. In the past when working with the GDB command line, I could get crashes and infinite loops for certain type. The good news is I haven't seen that problem using the VSCode integration.

Issue with <ArrayItems>

In essence the problem is that elements of ArrayItems sometimes don't display correctly. At first this seemed to be due to calling a function. For example when I had a TArray<SubString>, where TArray uses <ArrayItems> and had SubString using a function, it didn't work. If I place SubString inside of another struct type it did work.

As it turns out the problem is deeper, because if the elements are raw pointers, and then the pointed to type has a natvis description, that doesn't work. The type the element is pointing to seems to have some issues, specifically it cannot be accessed/cast via this. You may be able to access a member, but you are not able to take the address of the member. If you were you could work around the problem, by casting the first member to the actual type.

I did try casting the <ValuePointer> into a struct wrapping of the pointer type, but that didn't fix anything.

The other work around is that the watch window does work, when accessing a specific member. It does require writing out the full expression to get to the item.

This is perhaps the most irritating of current issues.

<CustomListItems> Doesn't Work

It appears as if <CustomListItems> just doesn't work. This is problematic for visualizing more complicated types such as hash maps.

In the end due to how I implement hash maps I can make it display something, somewhat readable via using <ArrayItems>.

Config/Natvis Error Reporting

If there is an error in Natvis or configuration it's hard to figure out what the problem is.

The logging options are set on a configuration basis. To enable natvis errors, you just need to enable "engineLogging"

			"logging": {
				"moduleLoad": true,
				"engineLogging": true,
				"trace": true,
			},

Another configuration issue is around triggering make with "-j'nproc'". This will make the compilation use all the cores that are available. The problem is how to call out to nproc. A way to work around this would be to trigger a script to initiate make with this option.

Workspace Issue

By default VSCode will open a folder, and then take that as being the root of your project. This is simple and convenient, but has an assumption that the directory name is meaningful for the root of the project. In my case I use subversion, and that means all project root directories are trunk, which makes it hard to tell whats going on as you flip between windows or roll over the VSCode instances and read the display text.

I worked around this using a .code-workspace file. This moved some configuration out of other files and disabled the use of "window.header". Never the less it seems like the better of the two scenarios.

Another option, perhaps for the future, would be to require the roots of subversion projects be the project name. So "MyProject/trunk/MyProject/...".

No Back Button

Using linux keyboard shortcuts

Not sure I like forwards key combination, I think it would be better to use say Ctrl Alt =/+. The options can be seen in the Go menu option.

Apparently you can get the back button.

On linux the "Window: Command Center" in on by default, but you don't see it because you also have to turn off the native title bar mode. Go to settings and search on "Window: Title bar style", and select custom.

Multi Target

Here the issue is around how to configure a project such that it works for multiple targets. For a specific scenario take the issue around natvis files. When developing with VS tooling, the full features of natvis are available and when on linux I have a subset, helped by the fact I can call a function. So I will need different natvis files depending on target.

The most obvious way is to make multiple configurations. The more sub projects and targets you have the more unwieldy this will become.

Perhaps there is a way to make cross platform differences available via multiple workspaces. For the makefile configuration this seems plausible because they can be defined in the workspace file. Other settings such as launch.json though don't seem to be configured that way though. This split is, at least currently to me, confusing. It seems to me it would be preferable to say have the .code-workspace specify files or directories holding other settings.

Clang

I ran across some random issues with gcc causing crashing. I thought I'd try compiling via clang, and I was able to build and run outside of VSCode. The good (?) news is that with a clang compilation the code ran as expected. The bad news is it's not 100% clear how to make this all work inside of VSCode.

If I try and compile via my makefile from within VSCode when it has been configured for clang I get an error about not finding clang++. From my regular terminal clang is installed.

I think I ran across this before, in that when I do gcc -v in a regular terminal and inside of VSCode terminal I get different versions. So how do you make clang available in the terminal?

Has some information but nothing about the lack of clang or why the terminal can access g++ but not clang.

The good news perhaps is that I can just build on the terminal, and debug in vscode.

Miscellaneous Issues

Extensions Used

Links

VSCode

C/C++

Natvis

Extensions

GDB

Assorted Discussions

Other Options