I have no idea what I am doing. I decided to use Vim as my only editor, I'm trying to set up autocompletion and syntax checking.
So I need to configure a .ccls file in the root of my project (and I don't want to generate a compile_commands.json file so please don't tell me about it). But there is no detailed documentation whatsoever on .ccls because all it does is use compiler flags, which of course I don't know; I have started not too long ago in C++ and I don't know any CMake, I was used to just run my code from the IDE!
I know that the default code to put in my .ccls is the path to my includes, which I do put (which are 5 paths that I get using clang++ -E -x c++ - -v < /dev/null) and I'm on mac btw. I put these, I get autocompletion, but my source breaks with errors telling things like iostream and every other header does not exist in /usr/local/include even though I provided 4 other paths (it really doesn't exit in /usr/local/include I don't know where iostream and those others are) and that I can't cout << "Hello, World!" << endl for example because ostream and char[] are incompatible and things like that. BTW even if I use compile_commands.json I still get errors it only fixes my header paths.
Can someone just explain how to use .ccls? No links, just plain explanation. Or at least a default configuration to get me going.
P.S Do I also need to provide paths to my project's header files?
This is my .ccls:
clang++
%cxx -std=c++17
%cxx -stdlib=libc++
%hxx --include=Global.h
%cxx -I/usr/local/include
%cxx -I/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1
%cxx -I/Library/Developer/CommandLineTools/usr/lib/clang/12.0.0/include
%cxx -I/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include
%cxx -I/Library/Developer/CommandLineTools/usr/include
I may be wrong, but I would keep it simple and simply put these lines in the .ccls file
clang
-std=c++17
-stdlib=libc++
-isystem/usr/local/include
-isystem/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1
-isystem/Library/Developer/CommandLineTools/usr/lib/clang/12.0.0/include
-isystem/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include
-isystem/Library/Developer/CommandLineTools/usr/include
If it works with this at first, then you could prefix all these lines with %cxx %c -- well, -std=c++17, -stdlib=libc++ and ..../include/c++/v1 are just for C++ though.
BTW, I'm not sure if the first line shall be clang or clang++.
Note: I've used -isystem because of the following:
You can use -I to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories. However, you should not use this option to add directories that contain vendor-supplied system header files; use -isystem for that. -- https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
Related
How can I tell where g++ was able to find an include file? Basically if I
#include <foo.h>
g++ will scan the search path, using any include options to add or alter the path. But, at the end of days, is there a way I can tell the absolute path of foo.h that g++ chose to compile? Especially relevant if there is more than one foo.h in the myriad of search paths.
Short of a way of accomplishing that... is there a way to get g++ to tell me what its final search path is after including defaults and all include options?
g++ -H ...
will also print the full path of include files in a format which shows which header includes which
This will give make dependencies which list absolute paths of include files:
gcc -M showtime.c
If you don't want the system includes (i.e. #include <something.h>) then use:
gcc -MM showtime.c
Sure use
g++ -E -dI ... (whatever the original command arguments were)
If your build process is very complicated...
constexpr static auto iWillBreak =
#include "where/the/heck/is/this/file.h"
This will (almost certainly) cause a compilation error near the top of the file in question. That should show you a compiler error with the path the compiler sees.
Obviously this is worse than the other answers, but sometimes this kind of hack is useful.
If you use -MM or one of the related options (-M, etc), you get just the list of headers that are included without having all the other preprocessor output (which you seem to get with the suggested g++ -E -dI solution).
For MSVC you can use the /showInclude option, which will display the files that are included.
(This was stated in a comment of Michael Burr on this answer but I wanted to make it more visible and therefore added it as a separate answer.)
Usability note: The compiler will emit this information to the standard error output which seems to be suppressed by default when using the windows command prompt. Use 2>&1 to redirect stderr to stdout to see it nonetheless.
Steps to reproduce.
Use Linux system where g++ defaults to standard older than c++17, but supports c++17 if given -std option
Create trivial C++ project outside of Eclipse with main.cpp:
#include <filesystem>
int main()
{
std::filesystem::path p;
return 0;
}
And Makefile:
all: a.out
a.out: main.cpp
g++ --std=c++17 -lstdc++fs main.cpp
Use Eclipse File->Import->C/C++->Existing Code as Makefile Project to create project over directory with those 2 files
Project builds properly, but indexer finds unresolved inclusion filesystem and type std::filesystem::path. In more complicated real world case there were no unresolved inclusions, but a lot of unresolved types were present.
Google finds lots of suggestions to set -std=c++17 in Properties->C/C++ Build->Settings->Tool Settings->GCC C++ Compiler->Miscellaneous->Other Flags but for imported makefile projects Tool Settings are disabled (my Eclipse version was 4.14, but I guess that this is the case for other versions too), sot this is not a way to go.
I found partial workaround for projects where you can use same flags for all files in the project. In Properties->C/C++ General->Preprocessor Include Paths, Marcos etc.->Providers tick CDT GCC Built-in Compiler Settings. This will enable to change contents of field Command to get compiler specs which in my case looked by default like this ${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}". Add into this command flags you need --- e.g. change it to ${COMMAND} ${FLAGS} -E -P -v -dD --std=c++17 "${INPUTS}". You may need to restart Eclipse afterwards and/or trigger index rebuild manually.
Contents of this field will be executed once with INPUTS replaced by path to an empty .C and once with an empty .c file. Output will be parsed by CDT to understand includes and preprocessor definitions used by your compiler.
If makefile project requires different options for C and C++ this seems to be still achievable but with a bit more work (you need to prepare some script which you will put into this field and this script will need call real compiler with appropriate options depending on language.
It seems that there is no possibility to tell indexer that different files use different options. I tried choosing cross compiler toolchain for indexer while importing project and then using this answer https://stackoverflow.com/a/27180772/31086 to select my "fake" tool-chain with empty prefix and path pointing to directory with scripts g++, gcc and as (which were calling beneath real compiler and logging what is going on), but indexer does not call compiler for each file, it uses its own logic to parse files, so no joy.
I can't make gcc compiler recognize complex paths in "includes".
Here's my toy "main.cpp" file (note the sub-directory in the include statement):
#include "sub/testlib.h"
int main()
{
testlib(6);
return 0;
}
Here's the path to the file "testlib.h" from the folder "main.cpp" lives in: ../lib/sub/testlib.h.
I'm specifying the include directory while compiling:
gcc -c -iquote../lib main.cpp
And the compiler yells at me:
main.cpp:1:10: fatal error: sub/testlib.h: No such file or directory
1 | #include "sub/testlib.h"
| ^~~~~~~~~~~~~~~
compilation terminated.
Of course I can make it compile by removing sub-directory from the path. But this is just an experiment I make after having failed to compile a real-world project. I can't freely change the files there.
How do I force gcc to treat sub-directories well in the includes? Is there a flag or some option that I'm missing here?
How do I force gcc to treat sub-directories well in the includes? Is there a flag or some option that I'm missing here?
Read the documentation of GCC, in particular the Invoking GCC chapter, the section on preprocessor options (e.g. -I include-dir or -H or -M, etc...), the documentation of the preprocessor. Try also g++ --help ; the -I include-directory flag can be repeated a lot of times and is probably what you need. Of course, order of arguments to the g++ program matters a lot. You probably want to use g++ not gcc when compiling or linking C++ programs.
Read also some documentation of C++ (maybe even the n3337 "draft" standard). Be aware of translation units, and of the role of the linker.
In practice, you want to drive GCC compilation using some build automation tool, such as GNU make or ninja or many others.
If you use GNU make, read its documentation then try make -p which shows the many built-in rules known to that software. Be aware of the many functions of make.
If you use ninja, read its documentation, you probably want to generate the build.ninja script it is using. You could generate it using a Python script or a Guile one (or your own C++ program, etc...).
Be aware that of course g++ will invoke some GNU binutils utilities (e.g. the assembler as or the linker ld).
Practically speaking, invoke g++ as g++ -Wall -Wextra -g to get warnings and debug information (of course with additional -I include-directory flags). Then use the gdb debugger. Once your program has few bugs, add optimization flags such as -O2
See also Clang, its static analyzer, Frama-C, and CompCert and, at end of 2020, Bismon.
Consider in some cases to generate some #include-d C++ code (e.g. with SWIG or ANTLR or Qt or your own script) or to extend GCC with your plugins.
Be of course aware of the Joel Test.
Reading the fine print of the -I switch in GCC, I'm rather shocked to find that using it on the command line overrides system includes. From the preprocessor docs
"You can use -I to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories."
They don't seem to be lying. On two different Ubuntu systems with GCC 7, if I create a file endian.h:
#error "This endian.h shouldn't be included"
...and then in the same directory create a main.cpp (or main.c, same difference):
#include <stdlib.h>
int main() {}
Then compiling with g++ main.cpp -I. -o main (or clang, same difference) gives me:
In file included from /usr/include/x86_64-linux-gnu/sys/types.h:194:0,
from /usr/include/stdlib.h:394,
from /usr/include/c++/7/cstdlib:75,
from /usr/include/c++/7/stdlib.h:36,
from main.cpp:1:
./endian.h:1:2: error: #error "This endian.h shouldn't be included"
So stdlib.h includes this types.h file, which on line 194 just says #include <endian.h>. My apparent misconception (and perhaps that of others) was that the angle brackets would have prevented this, but -I is stronger than I'd thought.
Though not strong enough, because you can't even fix it by sticking /usr/include in on the command line first, because:
"If a standard system include directory, or a directory specified with -isystem, is also specified with -I, the -I option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain."
Indeed, the verbose output for g++ -v main.cpp -I/usr/include -I. -o main leaves /usr/include at the bottom of the list:
#include "..." search starts here:
#include <...> search starts here:
.
/usr/include/c++/7
/usr/include/x86_64-linux-gnu/c++/7
/usr/include/c++/7/backward
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
Color me surprised. I guess to make this a question:
What legitimate reason is there for most projects to use -I considering this extremely serious issue? You can override arbitrary headers on systems based on incidental name collisions. Shouldn't pretty much everyone be using -iquote instead?
What legitimate reasons are there for -I over -iquote? -I is standardized (at least by POSIX) while -iquote isn't. (Practically, I'm using -I because tinycc (one of the compilers I want my project to compile with) doesn't support -iquote.)
How do projects manage with -I given the dangers? You'd have the includes wrapped in a directory and use -I to add the directory containing that directory.
filesystem: includes/mylib/endian.h
command line: -Iincludes
C/C++ file: #include "mylib/endian.h" //or <mylib/endian.h>
With that, as long as you don't clash on the mylib name, you don't clash (at least as far header names are concerned).
Looking back at the GCC manuals it looks like -iquote and other options were only added in GCC 4: https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options
So the use of "-I" is probably some combination of: habit, lazyness, backwards compatibility, ignorance of the new options, compatibility with other compilers.
The solution is to "namespace" your header files by putting them in sub directories. For example put your endian header in "include/mylib/endian.h" then add "-Iinclude" to the command line and you can #include "mylib/endian.h" which shouldn't conflict with other libraries or system libraries.
I this your premise that it's -I that's dangerous is false. The language leaves the search for header files with either form of #include sufficiently implementation-defined that it's unsafe to use header files that conflict with the names of the standard header files at all. Simply refrain from doing this.
An obvious case is cross-compilation. GCC suffers a bit from a historical UNIX assumption that you're always compiling for your local system, or at least something that's very close. That's why the compiler's header files are in the system root. The clean interface is missing.
In comparison, Windows assumes no compiler, and Windows compilers do not assume you're targeting the local system. That's why you can have a set of compilers and a set of SDK's installed.
Now in cross-compilation, GCC behaves much more like a compiler for Windows. It no longer assumes that you intend to use the local system headers, but lets you specify exactly which headers you want. And obviously, the same then goes for the libraries you link in.
Now note that when you do this, the set of replacement headers is designed to go on top of the base system. You can leave out headers in the replacement set if their implementation would be identical. E.g. chances are that <complex.h> is the same. There's not that much variation in complex number implementations. However, you can't randomly replace internal implementation bits like <endian.h>.
TL,DR : this option if for people who know what they're doing. "Being unsafe" is not an argument for the target audience.
It's been a while since I've dealt with C/C++, so forgive me if this is a ridiculously easy to answer question - I just don't quite know how to "Google" it.
I have a file, "MyFile.h" that includes file "includedFile.h". However, the compiler cannot find the file. Please see below picture:
What I'm doing is moving the project from an old Solaris box to a Linux box. The weird thing is that it worked on the Solaris box as-is but Linux is a little confused.
The makefile that I use for the project hasn't changed either which makes me think that it may be a compiler option...
So how do I tell the compiler on Linux where that include file is, or how do I specify it in "MyFile.h?"
With gcc and clang, you specify the include path using -I:
g++ -o myprogram main.cc extra.cc -I/usr/include/boost -I/my/extra/include/files
You can specify full paths in your files, as in #include "/path/to/my/includedfile.h", but I strongly discourage this as it forces everyone who wants to compile your code to comply with that directory layout.
Also relevant: Read the following link for the difference between #include <file> and #include "file" in gcc: http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
Assuming you are using g++, you pass a path with the -I flag.
g++ ..... -I<a path to your includes> -I<another path to includes>