Hey all, hope you're having a good day.
I'm competely new to c programming and I want to follow along to handmade hero to learn.
I don't however, want to go through it without having my basic LSP working in Neovim.
Has anyone else done this?
I cannot get it to recognize anything, it doesn't load header files.
I'm super lost as to what to do to get set up, and there isn't any lsp related setup resources that i could find.
it's only sublime text and atom, which if i remember correctly atom is defunct?
I'm on Windows 10, and use neovim with Clangd. or.. i want to.. any advice?
I expect clangd or any similar tools will not work well on Handmade Hero source code because its code base builds as unity build. Meaning .cpp files won't find correct declarations because includes are maintained in place where .cpp file itself is included. The .cpp files are not standalone translation units in such build.
Indeed. See this open issue: https://github.com/clangd/clangd/issues/45
I haven't found an existing solution for go-to-definition that works reliably for code bases structured this way.
Posting on this old thread in case anyone stumbles upon this in the future.. as it totally looks like the clangd team isn't willing to work on proper support for this, it seems that workarounds is all we have..
After fighting with this myself for a long time, the best workaround I have found yet is the one described in https://www.frogtoss.com/labs/clangd-with-unity-builds.html.
Essentially, assuming unity.cpp is your main (only) translation unit that includes all other .cpp files PLUS any necessary headers etc, what you do is:
#pragma once to the top of this file#include "unity.cpp" to the top of every other .cpp fileWhat this does is, it leaves your unity build unaffected, since the circular include in each .cpp component will be ignored (due to the #pragma). However, assuming your clangd is configured in the typical manner to compile each of your .cpp files individually, each of these compilations should now succeed since each .cpp file includes everything it needs at the very top.
This is probably still not perfect but it's miles better than the default clangd behaviour. I'm still testing out some kinks, my unity build is actually broken down per engine module, so there are definitely more complications there..
If anybody figures out a better system, I'd be super interested in hearing about it!
Whoever still wants to use clangd with benefits of unity builds - there is in fact solution! And it kinda makes you sure that you only use unity build hierarchy (might be good or bad, of course)
First, add .clangd file in your project directory. For example, I have this file structure:
S:
│ ...
│ .clangd <- you can have common configuration
└───HANDMADE
│ .clangd <- and project-specific (or even more inbetween)
├───build
│ └...
└───code
└...
Just in case you are interested what you can do with them(although I have them small) I left both files untouched. Here's my common s:/.clangd:
If: PathMatch: .*\.[h|h..|c|c..] CompileFlags: Compiler: clang-cl Add: [-FIunity_build.cpp] <- THIS IS WHAT YOU TOTALLY NEED Completion: ArgumentLists: Delimiters
And project-specific s:/handmade/.clangd(it inherits from common one, but also can override things if you want):
CompileFlags: Add: [-DHANDMADE_INTERNAL=1, -DHANDMADE_SLOW=1, -DHANDMADE_WIN32=1] <- this is stacked up on common added args and doesn't override
Second, you move out everything you need in every source file into one header, I named it unity_build.h. For example, here's mine:
#pragma once #include <stdint.h> // ...other standard/third-party headers used... #ifdef _WIN32 │ just an example #include <windows.h> │ that such constructions #include <dsound.h> │ go here too #include <xinput.h> │ #elif // ifdef ^ _WIN32 ^ | v __linux__ v │ // TODO: add headers │ #endif // ifdef ^ __linux__ ^ │ using u8 = uint8_t; // ...other typedefs... #define local_persist static // ...other macros... static constexpr f32 Pi32 = 3.141592653589793f; // ...other constants... (I use them like that instead of macros) // Basically everything that is(or can be) not defined in any of source-files, move out here // Then all headers #ifdef _WIN32 #include "win32_handmade.h" #endif // _WIN32 #include "handmade.h" // BUT NO SOURCE FILES HERE!!!
Then #include only this header in first line of every source file.
And finally make a corresponding source for this header, that just includes sources:
#include "unity_build.h" #ifdef _WIN32 #include "win32_handmade.cpp" #endif // _WIN32 #if HANDMADE_INTERNAL #include "handmade_internal.cpp" #endif #include "handmade.cpp"
That's it! Starting new project this way must be easier than migrating to this structure from other ones(even if it's just the same unity build without headers), but errors should guide you in either way, so it's not THAT hard.
You might think that there are some redundancies, and in fact at first I had a simpler build(that didn't need header files). It worked for me while I used clang++, but somehow clangd couldn't do this with clang-cl, that I decided to use instead at some point, since Casey used cl in the series. But this must work for both I believe, although I haven't tested it on clang++ again. I don't know how this even matters, and if there are compilers that don't work even with this, but I think for most(if not all) people this would work)
I guess I will go now and duplicate this in my github so more people know about this solution.