Compilation fails with #include "..." but not with #include <...> - c

I'm currently toying around with the C library NanoVG library. The library depends on OpenGL fucntions and has 2 header files nanovg.h and nanovg_gl.h. The latter file contains part of the implementation. For convenience, I have placed these two header files in /usr/include/nanovg.
When I try to compile the following code to an object file, gcc does not complain:
// working.c
#include <GL/gl.h>
#include <nanovg/nanovg.h>
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg/nanovg_gl.h>
(Command: gcc -c working.c -o working.o)
Now, I copy the header files from /usr/include/nanovg/ to the working directory, and replace the code with:
// notworking.c
#include <GL/gl.h>
#include "nanovg.h"
#define NANOVG_GL3_IMPLEMENTATION
#include "nanovg_gl.h"
(Command: gcc -c notworking.c -o notworking.o)
Gcc now complains that some OpenGL functions are not declared:
... (many more similar complaints)
src/nanovg_gl.h: In function ‘glnvg__renderDelete’:
src/nanovg_gl.h:1540:3: warning: implicit declaration of function ‘glDeleteBuffers’; did you mean ‘glSelectBuffer’? [-Wimplicit-function-declaration]
1540 | glDeleteBuffers(1, &gl->fragBuf);
| ^~~~~~~~~~~~~~~
...
Why does one file compile smoothly but not the other?
A bit deeper:
Using the cpp tool, I found that the difference between the two pre-processed files is limited to # directives but I don't see any difference as far as the "C content" goes. Below is a snippet of the pre-processed working.c. If I add the # lines from the pre-processed notworking.c, then gcc no longer compiles the pre-processed working.c and complains about a missing declaration for glDeleteBuffers.
// ...
if (gl ==
// # 1533 "src/nanovg_gl.h" 3 4 // <- uncomment this line and glDeleteBuffers is considered missing by gcc
((void *)0)
// # 1533 "src/nanovg_gl.h" // <- idem
) return;
glnvg__deleteShader(&gl->shader);
if (gl->fragBuf != 0)
glDeleteBuffers(1, &gl->fragBuf); // <- the function that gcc complains about is here
// ...
Edit: Just to make sure that I did not do anything sneaky that might have caused the difference, I followed the following steps which hopefully should be reproducible on another computer:
GCC version: gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0
Copy the version of GL/gl.h can be found here to working directory and call it glfoo.h
Copy the headers of nanovg (as found in the repo) to /usr/include/nanovg/ and nanovg/ (relative to working directory).
Save the following as test.c in the working dir:
#include "glfoo.h"
#include <nanovg/nanovg.h>
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg/nanovg_gl.h>
Run gcc -c test.c -o test.o => compilation works
Replace <...> with ".." on lines 2 and 4 and run command => compilation fails.
Just tried these exact steps and I was able to reproduce it.

After investigating this a bit I found the solution. gcc does not apply the same warning level to system headers as it does for "normal" files (this is mainly because system headers are sometimes doing weird things which are not backed up by the C standard, but are "safe" for the platform they are coming with).
The gcc documentation states (emphasis mine):
-Wsystem-headers:
Print warning messages for constructs found in system header files. Warnings from system headers are normally suppressed, on
the assumption that they usually do not indicate real problems and
would only make the compiler output harder to read. Using this
command-line option tells GCC to emit warnings from system headers as
if they occurred in user code. However, note that using -Wall in
conjunction with this option does not warn about unknown pragmas in
system headers—for that, -Wunknown-pragmas must also be used.
When you include nanovg via <...>, it is treated as a system header.
So doing gcc -Wsystem-headers working.c actually will bring on the warning.
Note that your code is neither working in working.c nor notworking.c, as working.c just hides the warning messages. The proper way to access any GL function beyond what is defined in GL 1.1 is to use the GL extension mechanism, which means you have to query the GL function pointers at run-time. Full GL loader libs like GLEW and glad can do that for you automatically. Many of these loaders (including GLEW and GLAD) work by re-#define-ing every GL function name to an internal function pointer, so when you include the header which comes with the loader, every GL function called in your code (and nanovg's) will be re-routed to the loader-libraries function pointers, and your code can actually work (provided you properly initialize the loader at run-time before any of the GL functions is called).

simply
#include <file.h>
include file from the path listed default to the compiler, while
#include "file.h"
include file from the current folder (where you are compiling).
As in your case , switching from <> to "" makes come files missing which makes that compiler error coming.

Related

Assimp multiple definition error in material.h when linking across multiple compilation units

I'm following the example provided at https://assimp.sourceforge.net/lib_html/usage.html to import a simple model using the assimp library. The first three lines in the example are the required include statements:
#include <assimp/cimport.h> // Plain-C interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
Of these, scene.h seems to be problematic. If you include it AND link against a compilation unit that also includes it, it gives multiple definition errors for aiGetMaterialFloat and aiGetMaterialInteger. A stripped down example is given below:
main.c:
#include <assimp/cimport.h> // Plain-C interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
#include "model.h"
//...
model.h:
#include <assimp/cimport.h> // Plain-C interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
//...
model.c
#include "model.h"
makefile:
main: main.c model
gcc main.c model.o
model: model.c model.h
gcc -c model.c
I'm using MinGW to compile these.
Now this DOES seem to compile if:
main.c does not include model.h, OR
the include statements are removed from model.h, OR
model.o is not linked when compiling main.c, OR
the import for scene.h is removed from one or both files
It will also compile just fine if the #includes are all moved to main.c and the model compilation unit is removed entirely.
Note that if one of the above conditions are met, this compiles just fine without a DLL or static library linked. The problem seems to be exclusively from including the header files.
I've done a lot of research and the only thing I could find is that it might be the inline specifier on these functions that was causing the issue. However, after removing the inline specifiers from the function definitions in the library header file, I'm still getting the same errors. I've been trying to solve this issue for hours and nothing seems to be working. Any ideas?

Disabling clang-tidy diagnostic

I'm trying to set up clang-tidy for enforcing naming conventions in a C project. This project is composed of multiple external sources and uses a plain makefile environment, thus no tool like cmake or bear is available to generate a compilation database.
This is also what I want: Using the custom environment I'd like to selectively invoke clang-tidy for each file that should be checked.
I was configuring the tool, mainly for the check readability-identifier-naming. For testing I have a .c and .h file, both in the same directory, with the following content:
dummy.c
#include "dummy.h"
#include "MISSING_module.h"
// EOF
dummy.h
#ifndef _DUMMY_H_
#define _DUMMY_H_
#include <stdlib.h>
// EOF
The command I'm invoking is
clang-tidy dummy.c -checks='-*,readability-identifier-naming' -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`
However, clang-tidy is still following the #include within the C-file and checks for existing headers:
dummy.h:4:10: error: 'stdlib.h' file not found [clang-diagnostic-error]
#include <stdlib.h>
^
Found compiler error(s).
Is there any way to disable this? clang-diagnostic-error is not even enabled as check. Or are there alternative tools I should know of to enforce naming conventions?
Look at the way you are using clang-tidy: the -- option is used to specify compilation options.
clang-diagnostic-error doesn't have anything to do with clang-tidy itself. Those are compiler warnings and you cannot turn them off. Clang-tidy needs the analyzed file to be compile-able to build an AST which it uses internally for the checks. You'll find more on clang-diagnostic-error in clang-tidy documentation.

Linking md5.h library for HTTP Digest sample implementation

I am struggling to compile a simple C program from RFC 2617. The program is digtest.c and it uses digcalc.c, another file from the sample implementation. The latter one depends on two files that my compiler doesn't know about:
#include <global.h>
#include <md5.h>
At first I got this error:
digcalc.c:5:20: fatal error: global.h: No such file or directory
I resolved that by changing <global.h> to <stddef.h>, it seems. But I still get this error:
digcalc.c:7:17: fatal error: md5.h: No such file or directory
Now, md5.h seems to refer to the file found in libbsd. So I installed libbsd-dev and tried to compile the files like this:
gcc digcalc.c digtest.c -o digtest -L/usr/lib/x86_64-linux-gnu -lbsd
where /usr/lib/x86_64-linux-gnu is the location of libbsd.so and libbsd.a files. However, this does not resolve the last compilation error.
Could anyone point out what am I missing here?
Figured it out. Had to change <md5.h> to <bsd/md5.h>, as noted on libbsd page.
So instead of the original headers in digcalc.c:
#include <global.h>
#include <md5.h>
I used:
#include <stddef.h>
#include <bsd/md5.h>
Also had to change function stricmp to strcasecmp, its POSIX equivalent. After that the sample code compiled seamlessly.

autoconf configure results in C std lib header related compile errors

I am attempting to build a project that comes with an automake/autoconf build system. This is a well-used project, so I'm skeptical about a problem with the configure scripts, makefiles, or code as I received them. It is likely some kind of environment, path, flag, etc problem - something on my end with simply running the right commands with the right parameters.
The configuration step seems to complete in a satisfactory way. When I run make, I'm shown a set of errors primarily of these types:
error: ‘TRUE’ undeclared here (not in a function)
error: ‘struct work’ has no member named ‘version’
error: expected ‘)’ before ‘PRIu64’
Let's focus on the last one, which I have spent time researching - and I suspect all the errors are related to missing definitions. Apparently the print-friendly extended definitions from the C standard library header file inttypes.h is not being found. However, in the configure step everything is claimed to be in order:
configure:4930: checking for inttypes.h
configure:4930: /usr/bin/x86_64-linux-gnu-gcc -c -g -O2 conftest.c >&5
configure:4930: $? = 0
configure:4930: result: yes
All the INTTYPES flags are set correctly if I look in confdefs.h, config.h, config.log Output Variables, etc:
HAVE_INTTYPES_H='1'
#define HAVE_INTTYPES_H 1
The problem is the same whether doing a native build, or cross-compiling (for arm-linux-gnueabihf, aka armhf).
The source .c file in question does have config.h included as you'd expect, which by my understanding via the m4 macros mechanic should be adding an
#include <inttypes.h>
line. Yes, as you may be inclined to ask, if I enter this line myself into the .c file it appears to work and the PRIu64 errors go away.
I'm left with wondering how to debug this type of problem - essentially, everything I am aware of tells me I've done the configure properly, but I'm left with a bogus make process. Aside from trying every ./configure tweak and trick I can find, I've started looking at the auto-generated Makefile.in itself, but nothing so far. Also looking into how I can get the C pre-processor to tell me which header files it's actually inserting.
EDIT: I've confirmed that the -DHAVE_CONFIG_H mechanic looks good through configure, config.log, Makefile, etc.
autoconf does not automatically produce #include directives. You need to do that on your own based on the HAVE_* macros. So you'll have to add something like this:
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
If these lines show up in confdefs.h, a temporary header file used by configure scripts, this does excuse your application from performing these #includes. If configure writes them to confdefs.h, this is solely for the benefit of other configure tests, and not for application use.
First, run make -n for the target that failed. This is probably some .o file; you may need some tweaking to get its path correctly.
Now you have the command used to compile your file. If you don't find the problem by meditating on this command, try to run it, adding the -E to force preprocessor output text instead of invoking the compiler.
Note that now the .o file will be text, and you must rebuild it without -E later.
You may find some preprocessor flags useful to get more details: -dM or -dD, or others.

Using Go code in an existing C project

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.
The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)
Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.
However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)
I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?
The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke
Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"
To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
func main() {}
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):
...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...
So that's enough to call the exported function. We can write a simple C program that calls it like so:
#include "foo.h"
int main(int argc, char **argv) {
PrintInt(42);
return 0;
}
We can compile it with a command like:
gcc -pthread foo.c foo.a -o foo
The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.
The code above work just fine, but gcc will complain about functions and headers.
The includes should be:
#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"
If you forget the #define _GNU_SOURCE, the gcc will complain:
warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]
If you forget the #include "mygopkg.h", the gcc will complain:
warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]
The last but not less important. The build command line I recommend for production code is:
go build -ldflags "-s -w" -buildmode c-archive -o mygopkg.a
It'll save you 53% size of final mygopkg.a.

Resources