Preprocessor flag to detect CGO build? - go

In a c file that's beside my go file and is compiled together via CGO, I'd like to check via preprocessor whether it's being compiled via go or not. I'd like to do this because, for example, I'd like to protect #include _cgo_export.h with #ifdef flags, since such header exists solely during compilation and I don't want my editor to warn about its absence.

From the documentation just do:
// #cgo CFLAGS: -DWHATEVER_YOU_WANT_TO_INDICATE_CGO=1
import "C"
(or just -D FOO if you don't want a value) or set CGO_CFLAGS in the environment.
You can see what is happening behind the scenes with go build -x.
For me it shows -D GOOS_freebsd -D GOARCH_amd64 while compiling the cgo generated _cgo_defun.c file, but only for that file and not to my own *.c files. So I don't think there are any usable predefined preprocessor flags (and the documentation also doesn't mention any).

Related

How can I suppress assembly files output by compilation proper?

I have some C++ library code that I want strictly compiled for a quick check, and I don't want any files produced to be used for later stages (assembly, linkage, etc.)
I can do
g++ -S main.cpp
but this will give me an assembly file that I'm just going to wind up deleting anyway.
Is there an option that will tell the compiler to just compile a source file but don't produce any files?
EDIT[0]: I'm using mingw on Windows.
gcc has the option -fsyntax-only:
Check the code for syntax errors, but don’t do anything beyond that.

Why do gcc and clang silently allow a standard include file to redefine macros?

Example code:
#define PROT_NONE 99
#include <sys/mman.h>
Both gcc and clang permit the above code fragment to compile; the PROT_NONE macro is redefined from within sys/mman.h with no warning. Looking at the actual header file, there is no #undef which would permit a redefinition.
This seems like a problem -- although this case is obviously contrived to show the problem, it does seem that identifier collisions between my code and the system header files can be silently ignored. The system header definition of PROT_NONE overrides my definition and doesn't even warn me that there's a potential problem. This seems to be specific to the system header file somehow; if I try to do the redefinition myself, I get the proper error.
My question is basically twofold:
Does anybody know the motivation behind allowing this behavior?
Is there any command line switch that will cause this to fail at the compilation stage?
What's happening/motivation
In both gnu and clang, warnings are suppressed in system headers.
The clang user manual just declares this is so:
Warnings are suppressed when they occur in system headers.
...but the gnu c preprocessor manual gives the following justification:
The header files declaring interfaces to the operating system and runtime libraries often cannot be written in strictly conforming C. Therefore, GCC gives code found in system headers special treatment.
Mitigation on the command line
Is there any command line switch that will cause this to fail at the compilation stage?
Yes. Make your system-headers non-system-headers.
In clang, you can do this merely with --no-system-header-prefix x/y/z, where x/y/z is a pattern matched starting at all system directories. For example, in your case, you can use --no-system-headers sys; or you can cherry pick further: --no-system-headers sys/mm (all files in a system directory included via the sys subdirectory that start with mm; it's just a prefix pattern, not a directory spec).
In gcc, this is a bit tricker. System headers by default are just headers in system directories, and there's no way to exclude a particular directory as a system directory. You can, however, ditch all system directories with -nostdinc, and add them back in as regular inclusion directories. For example:
gcc -nostdinc -I/usr/include -I/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include ...
You need -nostdinc; -I paths into your system inclusion paths just winds up being ignored.
GCC suppresses warnings in system headers by default. The reason is that the user usually cannot do anything about warnings generated by those headers because they cannot edit the code to fix those warnings. You can enable those warnings using -Wsystem-headers.
For your specific example, a redefinition of a macro not defined in a system header by a system header, GCC should probably warn even with -Wno-system-headers (it now has the infrastructure to do that). Someone already filed an RFE:
-Wno-system-headers hides warning caused by user header vs system header conflict

Assembler used by golang when building with and without cgo

Let's say I have a golang package, which contains some assembly code:
demopkg/
source1.go
source2.go
asm_amd64.s
If I try to build it using go build, toolchain will use go tool asm to assemble the *.s files.
But if I add Cgo to the mixture, by putting a single import "C" into any of the sources, go will switch to gcc assembler.
I can see it by executing go build -n. Calls to the /usr/local/go/pkg/tool/linux_amd64/asm from the first case get replaced by calls to gcc. Besides that, it starts complaining about broken syntax.
Is this behaviour documented, so I can rely on it for the maintaining of my package? Can I force go build to use one exact assembler?
Yes, it's in the cgo documentation
When the Go tool sees that one or more Go files use the special import
"C", it will look for other non-Go files in the directory and compile
them as part of the Go package. Any .c, .s, or .S files will be
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
the C and C++ files will be recompiled. The default C and C++
compilers may be changed by the CC and CXX environment variables,
respectively; those environment variables may include command line
options.

Override an external package's cgo compiler and linker flags?

Let's say I want to use some awesome go package. I can include it by:
import "github.com/really-awesome/project/foobar"
And inside that project's foobar.go file, it defines some cgo instructions like:
#cgo windows CFLAGS: -I C:/some-path/Include
#cgo windows LDFLAGS: -L C:/some-path/Lib -lfoobar
But if I have that foobar C dependency installed somewhere else, I would really need those lines to say:
#cgo windows CFLAGS: -I C:/different-path/Include
#cgo windows LDFLAGS: -L C:/different-path/Lib -lfoobar
Is there a way to override or trump where cgo is looking for these dependencies? Right now my fix is to manually edit those two lines after running go get ./... which will fetch the github.comreally-awesome/project/foobar code.
NOTE: I'm using the MinGw compiler, though I doubt that matters.
update:
I have tried adding flags to go build to no avail:
go build -x -gcflags="-I C:/different/include -L C:/different-path/lib -lfoobar"
go build -x -ccflags="-I C:/different/include" -ldflags="-L C:/different-path/lib -lfoobar"
With the -x argument I see the printout of flags and they don't include the ones I am setting on the command line. Perhaps the #cgo CFLAGS/LDFLAGS statements at the top of the external go package squash what I am telling it to use...
You can do this by setting the CGO_CPPFLAGS and CGO_LDFLAGS environment variables.
For example, on my MacBook, Homebrew is installed in ~/.homebrew (instead of /usr/local), so when I try to go get packages with native bindings they can't find the headers and libs.
To fix that I added these two lines to my ~/.zshenv file:
export CGO_CPPFLAGS="-I $BREW_HOME/include"
export CGO_LDFLAGS="-L $BREW_HOME/lib"
This is kind of the role filled by #cgo pkgconfig: foobar. If the library had been written that way, it would pick up the correct paths from foobar's pkgconfig definition.
I realise its not a direct answer to the question, and that pkgconfig isn't exactly a native windows tool... I'd be interested to hear if any other solutions exist.

Purpose of __USE_XOPEN2K8 and how to set it?

I'm trying to compile the gtk stack (the last gtk2 version, 2.24), and I am getting a bunch of errors that seem related. Namely, the __locale_t can't be found from string.h and time.h, and LC_ALL_MASK can't be found either (should be in locale.h).
I found that all of these problems are related to __USE_XOPEN2K8 not being #defined. What is __USE_XOPEN2K8 for, and how can I set it propertly?
For example, do I have to pass a flag to ./configure for glib, gtk, ... or do I have to change something already while building gcc or glibc̲? I'd rather not just sprinkle #define __USE_XOPEN2K8 in to my sources without knowing what it does. Note I'm using gcc-4.6.3 and glibc-2.16.0 which are installed in a nonstandard prefix, as I'm trying to get the gtk libraries to work on an older CentOS (5.8) that only includes older versions.
Also note the missing __locale_t is mentioned in several places, e.g. this bugreport. I could just add #include <xlocale.h> in some files, but it seems the proper solution would be to get __USE_XOPEN2K8 to be set.
Edit: I've found this thread describing the problem. Apparently, headers of the host system get "fixincluded" into the headers of the new compiler. The linked post suggests to edit features.h. Does anyone know if I have to recompile gcc / glibc afterwards (and how to get it to pick up the new features.h, rather than overwriting it)?
When __USE_GNU is defined, __USE_XOPEN2K8 is always defined as well, unless you
are explicitly defining or undefining these macros, which you must not do.
Use _GNU_SOURCE, _XOPEN_SOURCE {500,600,700,...} etc. macros before including
the first header instead. This is the recommended way to select the GNU feature set in glibc headers, together with defining it on the command line (-D_GNU_SOURCE).
Alternatively, you can try specifying GNU extension usage to gcc through the -std command line switch (gnu89, gnu99, and so forth).
On CentOS7 with gcc 4.6 we had to use -D_XOPEN_SOURCE=700 -D__USE_XOPEN2K8
The glibc __USE_* macros are internal macros used to implement feature selection. The supported way to set them is to define feature test macros such as -D_GNU_SOURCE:
Feature Test Macros
These macros are needed because glibc supports many standards and GNU extensions, and these features are in conflict with each other, mostly due to the lack of namespaces in C. For example, C and POSIX allow you to define a global variable called secure_getenv (because the identifier is not reserved or otherwise used by those standards), but such a program will not work if you compile with _GNUS_SOURCE and include <stdlib.h> because glibc provides a function called secure_getenv.
<xlocale.h> is an internal glibc header (a comment within the header file says so) and will no longer be available in glibc 2.26.
As I know when we use the complier, it's behavior depends on some ENV macros, which saved in feature.h. So you can configure your complier by modifyinfg it.
Fisrt,you need use g++ -E youfile > log, to see which feature.h file your complier use, and then use g++ -E -dM /path/to/feature.h>log, to find the __USE_XOPEN2K8, if you can't find it. Add #define __USE_XOPEN2K8 1 at the end of the file.You know may be you have do some configure wrong when you install you complier.

Resources