I'm using cgo to wrap a C library and have run into a strange set of linker errors. I've boiled the problem down to the following:
A file header.h contains
#ifndef HEADER_H
#define HEADER_H
#define CONSTANT1 ("")
#define CONSTANT2 ""
#define CONSTANT3 ((char*)0)
#define CONSTANT4 (char*)0
#endif /* HEADER_H */
And test.go contains
package main
/*
#include "header.h"
*/
import "C"
func main() {
_ = C.CONSTANT1
_ = C.CONSTANT2
_ = C.CONSTANT3
_ = C.CONSTANT4
}
Upon running go run test.go I get the following error:
# command-line-arguments
... _cgo_main.o:(.data.rel+0x0): undefined reference to `CONSTANT4'
... _cgo_main.o:(.data.rel+0x8): undefined reference to `CONSTANT3'
... _cgo_main.o:(.data.rel+0x10): undefined reference to `CONSTANT1'
collect2: ld returned 1 exit status
I have two questions about this:
Why does the linker have anything to do with pre-defined constants?
Why do CONSTANT1, CONSTANT3, CONSTANT4 show up as undefined, but not CONSTANT2?
Thanks in advance.
*Edit: Constants defined as other values (e.g. ints) work fine.
*Edit2: Using go version go1.1.2 linux/amd64
*Edit3: A complete example of failure:
I'm working with the C OpenLDAP library and would like to use the LDAP_SASL_SIMPLE constant. It's defined in ldap.h as
#define LDAP_SASL_SIMPLE ((char*)0)
#define LDAP_SASL_NULL ("")
The LDAP_SASL_NULL constant gives the same error.
A minimal demonstrative go program:
package main
/*
#cgo LDFLAGS: -lldap
#include <ldap.h>
*/
import "C"
func main() {
_ = C.LDAP_SASL_SIMPLE
}
I did originally answer something different based on how I thought cgo works. But if CONSTANT2 is recognized by cgo, something different might be the reason. Could you please:
run the tool nm on the library file and tell whether the output contains CONSTANT2 or any other constants you refer to that were at the same time established through #define. A library might declare a #define constant at the same time as a global symbol to get around compatibility issues.
provide a minimal working example of your problem if possible. This is, an example that can be compiled by someone who reads your post and exhibits your problem. Your question looks like it may miss some important parts to answer it. For instance, it would be nice to know the actual library you have problems with.
original answer
If you use #define, you do not establish anything the compiler will actually see. A #define is a preprocessing directive that is removed before parsing. To establish constants the compiler (and thus cgo) can see, actually declare them:
const char *CONSTANT1 = "";
const char *CONSTANT2 = "";
const char *CONSTANT3 = (char*)0;
const char *CONSTANT4 = (char*)0;
If you cannot touch the header, there is typically not much you can do; you basically have to duplicate all constants in the Go part of your code:
const (
CONSTANT1 = "",
CONSTANT2 = "",
CONSTANT3 = nil,
CONSTANT4 = nil,
)
You could try complex tricks like running cpp over your Go code, but this is likely to cause more trouble than it would solve problems.
Related
I have static library file(lib_XXX.a) with global variable defined in it. I am trying to access the global variable in my executable(exe_XXX.o).
Linker error is coming. Any help would be thankful.
Languae : c
OS : Ubuntu gcc compiler
Sample as follows
exe_xxx.o module has 2 files resource.h and main.c
resource.h code as follows :
#ifndef RESOURCE_H
#define RESOURCE_H
#define APL
extern const StructTest g_AplObjDef;
const StructTest g_AplObjDef = {
abc, def, ghi,
....
};
#endif //APL
main.c code as follows:
#include "resource.h"
....
....
....
lib_xxx.a has another main.c in it. Its sample code as follows:
#include "resource.h"
int main()
{
#if defined(APL)
fun1(g_AplObjDef);
#endif
}
I suspect the reason is because resource.h included in both the main.c files.
I couldn't way to get rid of this. Can anyone help ?
Error details:
/lib_XXX.a(lib_XXX_a-main.o):(.data.rel.ro.local+0x40): `g_AplObjDef' が重複して定義されています
/exe_xxx-main.o:(.data.rel.ro.local+0x260): ここで最初に定義されています
Above error is in Japanese.. 1st line says "Duplicate is defined". 2nd line says "Here it is defined"
This part:
const StructTest g_AplObjDef = {
abc, def, ghi,
....
};
is a definition, and should not be in a header. Move it to
a .c file.
The reason for this is that header files are textually inserted, so if a header has a definition, and is included from multiple translation units, the symbol will be defined multiple times, which is an error.
Here you are defining a variable in the header
const StructTest g_AplObjDef =
You should only declare, which you did the line before.
This definition should go into a code file, accessing it will be possible by the knowledge provded by the declaration in the header. But the definition in the header will be done in each code file which includes it, which causes the redundant definition mentioned in the error message.
Moving the definition (as you now have it in the header, including the {...} into the libs code file should help.
Note that having two main() will probably get you into trouble, I only focus this answer on the double definition of the variable.
I'm currently trying to build a Golang wrapper for the NOVAS C package (an astrometry/astronomy package) by using cgo. NOVAS is essentially 'installed' by placing the source files in whatever directory you happen to be working in (no compiled library files present), hence I believe I need to include the .c files I will be using (which is in a folder one directory down from the .go file.
As such, I'm trying to test this by creating a test .go program which itself calls a function within novas.c. However, the program fails to compile, apparently because there are multiple undefined references to functions present within math.h; this is strange because math.h is included both in my .go file and the C files I intend to use.
go run novasTest.go
# command-line-arguments
/tmp/go-build681583835/b001/_x002.o: In function `equ2gal':
./Cdist/novas.c:1995: undefined reference to `sincos'
./Cdist/novas.c:1996: undefined reference to `sincos'
./Cdist/novas.c:2033: undefined reference to `atan2'
./Cdist/novas.c:2025: undefined reference to `atan2'
./Cdist/novas.c:2022: undefined reference to `sqrt'
/tmp/go-build681583835/b001/_x002.o: In function `era':
./Cdist/novas.c:3242: undefined reference to `fmod'
./Cdist/novas.c:3242: undefined reference to `fmod'
...(etcetera)
I'm running on Ubuntu 18.04 (x64) within a VirtualBox VM instance. Am I missing a specific line here?
My go program looks like this:
package main
/*
#include "Cdist/novas.h"
#include "Cdist/novas.c"
#include "Cdist/novascon.c"
#include "Cdist/nutation.c"
#include <math.h>
*/
import "C"
import "log"
func main() {
log.Println("Test of NOVAS function")
var JulianHigh C.double
var JulianLow C.double
...
var Z C.double
// Test values
JulianHigh = 2458953.5
JulianLow = 1.0
...
Z = -1.437110810486059E+03
vCel := make([]C.double,0) //Create the array to pass to the function.
vCel = append(vCel, X)
...
vTerFirst := &(vTer[0])
C.cel2ter(JulianHigh,JulianLow,DeltaT,Method,Accuracy,Option,PolarX,PolarY,vCelFirst,vTerFirst)
log.Println("C function completed processing.")
}
The C program is too large to include, so I will instead show the relevant parts of the novas.h file and novas.c file.
C File:
/*
...
novas.c: Main library
...
*/
#ifndef _NOVAS_
#include "novas.h"
#endif
#include <math.h>
... //(other functions follow until the necessary one)
/********cel2ter */
short int cel2ter (double jd_ut_high, double jd_ut_low, double delta_t,
short int method, short int accuracy, short int option,
double xp, double yp, double *vec1,
double *vec2)
/*
------------------------------------------------------------------------
PURPOSE:
This function...
Note that the function itself relies on functions that make calls from the other files I included.
.h file:
/*
...
novas.h: Header file for novas.c
...
*/
#ifndef _NOVAS_
#define _NOVAS_
#ifndef __STDIO__
#include <stdio.h>
#endif
#ifndef __MATH__
#include <math.h>
#endif
#ifndef __STRING__
#include <string.h>
#endif
...
You need a directive to tell the go linker to link with c's math library. The header math.h doesn't contain implementations of the math functions: only their declarations (to a first approximation).
Anyway, you need to add this line in a comment in your go file:
#cgo LDFLAGS: -lm
-l means "link with this library", and m is the name of C's maths library.
This question already has answers here:
"#include" a text file in a C program as a char[]
(21 answers)
C/C++, can you #include a file into a string literal? [duplicate]
(7 answers)
Closed 3 years ago.
I'm working on part of a C program where a user inputs a network filter string (think Wireshark).
A filter string like, for example
(s->field_a == 1 || s->field_c <= 10) && ! (s->field_c % 2)
Is entered by the user and pasted into a function in a temporary file, which is compiled as a shared lib and loaded wit dlopen. The function simply evaluates the string.
Now, the type of "s" struct is defined in some .h file, let's say struct.h.
Obviously struct.h won't be available for the runtime compilation. I can just paste its content to a string and fprintf it, but then I'd have to re-paste it whenever I change the header.
I could write a script that'd do it during building, but maybe there's a better option.
Is there a way to "paste" the content of the file as a string using e.g. the preprocessor?
Some code to illustrate what I'm trying to do:
struct.h:
struct example_struct
{
int field_a;
int field_b;
int field_c;
};
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "struct.h"
int main(int argc, char *argv[]) {
struct example_struct s;
char filter_string[] = "(s->field_a == 1 || s->field_c <= 10) && ! (s->field_c % 2)"; // what the user can input
FILE *f = fopen("/tmp/prog.c","w");
// here I'd like to insert contents of struct.h into f
fprintf(f, "int filter(struct example_struct * s) {\n");
fprintf(f, "return (%s);}\n", filter_string);
fclose(f);
system("gcc /tmp/prog.c -o /tmp/prog.so -shared -fPIC");
// load and use function...
}
Edit:
I don't need an actual representation as a char[], it can be a string literal.
I'm trying not to use xxd or some other tool before building the program, I can do that fine by inserting the text with a python script or whatever. I'm just curious if a "pure" solution is possible.
Is there a way to "paste" the content of the file as a string using e.g. the preprocessor?
[...]
I'm trying not to use xxd or some other tool before building the program, I can do that fine by inserting the text with a python script or whatever. I'm just curious if a "pure" solution is possible.
The C language does not have a built-in feature for including compile-time file contents as character array contents, whether in string literal form or any other kind of initializer form. If you want that then you need to use some kind of code generator.
But I'd like to challenge your assumptions for a moment. You say,
Obviously struct.h won't be available for the runtime compilation.
, but I don't see why that has to be true. At least in principle, nothing prevents you from packaging the header file together with the program, installing it in a location known to the program (or that the program can discover or be configured for) and using it as a normal header.
Found a trick with defines that'll do it here.
It's a bit wacky, but it does exactly what I wanted.
In struct.h:
#ifndef STRINGIFY
#define STRINGIFY(x) x
#endif
STRINGIFY (
struct example_struct
{
int field_a;
int field_b;
int field_c;
}; )
#undef STRINGIFY
That way when it's included as a regular file, the define does nothing.
In main.c I can now insert the string as follows:
#define STRINGIFY(x) #x
const char * header_string =
#include "struct.h"
;
#undef STRINGIFY
Code from "struct.h" will be included as a string literal.
It is not a language question, but some development systems could help. For example the Windows API has the notion of resource which allows to embed a file in an executable and access that resource as run time more or less as if it were an internal file.
According to those other SO questions:
Embedding resources in executable using GCC
C/C++ with GCC: Statically add resource files to executable/library
Is there a Linux equivalent of Windows' "resource files"?
(and probably others: just follow the possible duplicate links), there are various ways with gcc on Linux from directly using the ld linker, to using external tools like ImageMagick.
But IMHO there is nothing wrong in just including the .h include file into the pack of distributable files that are required to use the application.
I've been running into a compiler warning:
version.h:47: warning: (1478) initial value for "_svn_string_revision" differs to that in version.h:47
the corresponding version.h file looks like this:
#ifndef _VERSION_H_
#define _VERSION_H_
#define SVN_REVISION_NUMBER 31
const char *svn_string_revision = "31"; // line 47
#endif //_VERSION_H_
Usage:
main.c:
#include "version.h"
// I do not use svn_string_revision here.
// I only use SVN_REVISION_NUMBER
#pragma config IDLOC3=SVN_REVISION_NUMBER
otherfile.c:
#include "version.h"
// still no usage of svn_string_revision, only this:
EUSART_Write(SVN_REVISION_NUMBER);
So far this is descriptive and clear. I assume the problem is that the const char string is defined in a header file, which gets included in more than one source code file. So the compiler sees more than one "svn_string_revision" variable and treats it as redeclaration. But normally the value should be always the same. My version.h file is an auto generated file which gets regenerated prior to every build.
Has somebody encountered this before, and how can I handle that?
The clean approach would be to use a version.h file complemented with a version.c, where the header declares
extern const char *svn_string_revision;
and the source
const char *svn_string_revision = "31";
But this would require me to rewrite the automated code generation, which I would like to avoid.
Long story short, my questions are:
Is my understanding of the warning correct?
How can I avoid those warnings gracefully, given that I don't want to split up version.h into a .c and .h file
First solution :
static const char *svn_string_revision = "31";
The static will make the variable local to each C file, so no conflict can occur. Since it is a read only constant it should be fine. However, this means there will be many copies of the variable in the program. A good compiler can optimize this, but in my experience, I'm not sure XC8 will do that.
Second solution, probably better :
#define SVN_REVISION_NUMBER 31
#define STRINGIFY(s) #s
extern const char *svn_string_revision;
// in version.c
const char *svn_string_revision = STRINGIFY(SVN_REVISION_NUMBER);
Or just :
#define SVN_REVISION_NUMBER 31
#define VERSION_STRING "31"
extern const char *svn_string_revision;
// in version.c
const char *svn_string_revision = VERSION_STRING;
You could also just remove svn_string_revision and use VERSION_STRING instead, but you should check before that XC8 doesn't create many copies of the string.
I'm trying to figure out how to build a variable string for the #include statement using GCC.
The idea is that for each source module I have written, I want to include as a header, a dynamically generated C source, that was created earlier in the build process.
Generating this file is not an issue. Including it, unfortunately, is.
What I have so far is (identities.h):
// identities.h
# define PASTER2(str) #str
# define PASTER(str) PASTER2(str ## .iden)
# define EVALUATOR(x) PASTER(x)
# define IDENTITIES_FILE EVALUATOR(__FILE__)
# include IDENTITIES_FILE
Ideally, this would be used like so (main.c):
//main.c
# include "identities.h"
int main() {return 0;}
Which would be expanded in a single pass by the preprocessor before compilation to yield:
//main.c (preprocessed)
# include "main.c.iden"
int main() {return 0;}
The two levels of indirection I'm using (PASTER and EVALUATOR) are a result of this post.
Unfortunately, this is not working and I am left with the error:
obj/win32/dbg/main.o
In file included from main.c:1:0:
identities.h:42:1: error: #include expects "FILENAME" or <FILENAME>
I think the problem is that the include statement is missing quotes.. Any ideas?
This is actually done in the Linux source tree; See line 100 of compiler-gcc.h.
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(__GNUC__)
I'm trying to figure out how to build a variable string for the #include statement using GCC.
This token pastes the value of __GNUC__ to a string; "linux/compiler-gcc" __GNUC__ ".h" and then stringifies the result. This maybe a gcc pre-processor extension.
Here is an example,
t1.h
#define FOO 10
t2.h
#define FOO 20
a.c
#ifndef VERSION
#define VERSION 1
#endif
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(t##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(VERSION)
#include <stdio.h>
int main(void)
{
printf("FOO is %d\n", FOO);
return 0;
}
Here are two compiles,
g++ -o a a.cc
g++ -DVERSION=2 -o a a.cc
The output of either compile gives expected result.
As with the Linux source, you can key off of gcc pre-defined values. echo | g++ -dM -E - will give a list.
For your case, you can use the makefile to pass a define to the compile to allow dynamic inclusion of the generated header without altering the source. But then a simple alternative is just to run sed, etc on a template source file and replace it with the known include name.
Either technique is good for generating test fixtures, etc. However, for compiler feature discovery, this is a better method. For programmers who use IDEs, this might be their only choice.
I am fairly certain you can't do what you want, __FILE__ returns a string and ## works on tokens and there is no CPP string concat preprocessor macro. Normally this is gotten around due to the fact that two strings in succession e.g.
"Hello" " World"
will be treated as a single string by the C++ parser. However, #include is part of the preprocessor, and thus cannot take advantage of that fact.
Old answer:
Why are you doing this
{ #str, str ## .iden }
I'm certain that's not preprocessor syntax; what do you hope to achieve via that? Have you tried just:
str ## .iden
A '{' could explain the error you are getting.
What about BOOST_PP_STRINGIZE from the Boost Preprocessor library . It is specifically made to add quotes around a name.
Skipping the whole inclusion syntax thing for a while, I don't understand what your code is trying to do. You say:
# define PASTER(str) { #str, str ## .iden }
You give it main.c and expect "main.c.iden", but that returns {"main.c", main.c.iden }.
Are instead you looking for this?
#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
You cannot use preprocessor like this. You have to supply a filename to the #include directive, it can't be some other macro.