Related topic:
Why does const imply internal linkage in c++, when it doesn't in C?
I was following GCC visibility wiki to add visibility to my shared library.
It generates a warning when I'm compiling my source file
warning: 'visibility' attribute ignored [-Wattributes]
Here's my code:
// my_shared_lib.h
#if __GNUC__ >= 4
#define DLL_API __attribute__((visibility("default")))
#define DLL_LOCAL __attribute__((visibility("hidden")))
#else
#define DLL_API
#define DLL_LOCAL
#endif
DLL_LOCAL const int my_local_var;
It generate following warning while compiling:
my_shared_lib.h: 'visibility' attribute ignored [-Wattributes]
DLL_LOCAL const int my_local_var;
^
Here's the entire building message:
make all
Building file: ../src/my_shared_lib.cc
Invoking: Cross G++ Compiler
g++-mp-4.8 -O3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"src/my_shared_lib.d" -MT"src/my_shared_lib.d" -o "src/my_shared_lib.o" "../src/my_shared_lib.cc"
my_shared_lib.h: 'visibility' attribute ignored [-Wattributes]
DLL_LOCAL const int my_local_var;
^
Finished building: ../src/my_shared_lib.cc
Can anyone tell me how to silent this warning and why this warning happened?
Is it because const variable are hidden by default?
PS.
I'm using g++ 4.8
You can silence the warning by passing -Wno-attributes to the compilation.
The warning is happening because, as the related question and answer mentions, in C++ const objects automatically have internal linkage unless they're explicitly marked as extern; i.e. they're hidden by default. The rationale is to encourage putting these const values into header files as-is (i.e. in the form const int x = value;). If they were public by default, then you would suffer multiple-linkage issues if the same variable appeared across multiple .cpp or .o files, which is what would happen if they were placed in .h files without the local linkage rule.
You should also be seeing a warning/error:
my_shared_lib.h:...: error: uninitialized const 'my_local_var' [-fpermissive]
which is a variation of the error because the const is implicitly static unless otherwise mentioned.
How do you fix this?
Firstly, use the const properly in the header when using C++, it's:
const int my_local_var = VALUE;
If you're sharing this .h file amongst C and C++ code then your choices are:
Don't make it const - that's actually meaningless for the C code, and prevents you from accomplishing the private, declared in the header and defined in a .c file but not exposed in the resulting .so
Use a #define - yes, it's ugly, but this is more semantically correct than using a const for C code as it prevents you from accidentally changing the value by erroneous assignment.
declare it in the .h as:
...
DLL_LOCAL extern const int my_local_var;
and then define it in the .cc/.cpp file as:
#include "my_shared_lib.h"
const int my_local_var = 42;
You need to add in the #include or else it doesn't get the extern which allows it to be exposed for linking in the .o files that make up the .so without getting it exposed in the .so itself.
and so we have (on a mac, but the premise is the same):
Header:
$ cat wodge.h
#define PRIVATE __attribute__((visibility("hidden")))
#define PUBLIC __attribute__((visibility("default")))
PRIVATE extern const int my_local_var;
int do_with_x(int x);
First C++ file:
$ cat wodge.cc
#include "wodge.h"
int
do_with_x(int y)
{
return my_local_var * y;
}
Second C++ file - definition of value:
$ cat wodge2.cc
#include "wodge.h"
const int my_local_var = 42;
Compile and show the resulting symbol table:
$ g++-4.8 -c -O3 -Wall -o wodge.o wodge.cc
$ g++-4.8 -c -O3 -Wall -o wodge2.o wodge2.cc
$ g++-4.8 -shared -o foo.dylib *.o
$ nm foo.dylib
0000000000000fb0 T __Z9do_with_xi
0000000000000fbc s _my_local_var
U dyld_stub_binder
Related
Im' trying to port a home made software from AIX to "Red Hat Enterprise Linux 7.8"
I'm facing "undefined reference to" errors at link time and, for now, I can't find where I screwed up.
The goal is to generate an executable from 2 homemade shared librairies (msi and atmi), some object previously compiled (MsiServices.o) and a C program (pingsrv.c).
Below is the command :
gcc -DWall -o bin/pingsrv -DUNIX -I. -g -DUNIX -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -I/home/vgi/git/msi-tools/ping/server/target/msi/include/yaml-cpp -I/home/vgi/git/msi-tools/ping/server/target/msi/include/apr-1 -I/home/vgi/git/msi-tools/ping/server/target/msi/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi-tools/ping/server/target/msi/include /tmp/MsiServices.o ./pingsrv.c -L/home/vgi/git/msi-tools/ping/server/target/msi/lib -lmsi -lactivemq-cpp -llog4cxx -latmi -lapr-1 -laprutil-1 -lexpat -lstdc++ -lyaml-cpp
Errors appears a link time:
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpreturn'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_tpcall'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libmsi.so: undefined reference to `msi::service::optarg'
/home/vgi/git/msi-tools/ping/server/target/msi/lib/libatmi.so: undefined reference to `Msi_userlog'
Library atmi is written in C and is able to call some C++ instance methods by using wrappers:
...
typedef struct MsiScheduler MsiScheduler ;
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
...
extern void tpreturn(int rval, long rcode, char * data, long len, long flags)
{
assert(vg_Consumer != NULL) ;
Msi_tpreturn(vg_Consumer,rval,rcode,data,len,flags) ;
}
Wrappers called by this library are defined in another library called msi. Wrappers are defined in a C++ source file (MsiScheduler.cpp):
void Msi_tpreturn(MsiScheduler * c,int ret,long code,char *data,long len,long flags)
{
TypedBuffer* buffer = NULL ;
if (data != NULL)
{
buffer = TypedBuffer::createBuffer(getType(data),data,len) ;
}
MsiReply * reply = MsiReply::createReply(ret,code,buffer) ;
c->tpreturn(reply) ;
if (data != NULL)
{
freebuf(data) ;
}
delete reply ;
}
int Msi_tpcall(MsiScheduler * c,char *svc, char *idata, long ilen, char **odata, long *olen, long flags)
{
...
}
void Msi_userlog(MsiScheduler *c ,char* str)
{
c->userlog(str) ;
}
header file (MsiScheduler.h) contains this fragment :
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
extern void Msi_tpreturn(MsiScheduler *,int, long , char *, long, long);
extern void Msi_userlog(MsiScheduler *,char*) ;
extern int Msi_tpcall(MsiScheduler *,char *svc, char *idata, long ilen, char **odata, long *olen, long flags) ;
#else
extern void Msi_tpreturn();
extern void Msi_userlog() ;
extern int Msi_tpcall() ;
#endif
#ifdef __cplusplus
}
#endif
Librairies are constructed like that:
g++ -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o MsiScheduler.o -c MsiScheduler.cpp
...
g++ -shared MsiUtil.o MsiConfig.o MsiInstrumentation.o MsiMetric.o MsiService.o MsiExceptions.o MsiCharsetConverter.o MsiTypes.o MsiMessage.o MsiMessageUtil.o MsiScheduler.o MsiServer.o -o libmsi.so
...
gcc -g -fPIC -Wall -I/home/vgi/git/msi/msi-service/target/ext/include/apr-1 -I/home/vgi/git/msi/msi-service/target/ext/include/activemq-cpp-3.9.4 -I/home/vgi/git/msi/msi-service/target/ext/include/yaml-cpp -I/home/vgi/git/msi/msi-service/target/ext/include -I/home/vgi/git/msi/msi-service/target/ext/include -I../lib/inc -I./ -o atmi.o -c atmi.c
gcc -shared atmi.o memmngt.o -o libatmi.so
FYI, everything compile and link well on AIX OS (with xlc,xlC commands).
I also tried to change librairies order for linking command, without success.
I guess there is something specific to linux/gcc but I haven't found it yet.
libmsi.so:0000000000034f20 T _Z10Msi_tpcallPN3msi7service12MsiSchedulerEPcS3_lPS3_Pll
libmsi.so:0000000000035138 T _Z11Msi_userlogPN3msi7service12MsiSchedulerEPc
libmsi.so:0000000000034e55 T _Z12Msi_tpreturnPN3msi7service12MsiSchedulerEilPcll
libatmi.so: U Msi_tpcall
libatmi.so: U Msi_tpreturn
libatmi.so: U Msi_userlog
In your nm output, the T's mean that the symbol on the right is defined in libmsi.so, and the U's mean that the symbol on the right is needed by libatmi.so. But obviously, the names of these symbols don't match up. The names in libmsi.so have the C++ mangling which helps keep overloaded functions separate.
This means the extern "C" did not apply to the function definitions when compiling MsiScheduler.cpp. Make sure it includes MsiScheduler.h, and that part of the header is not skipped by any #if. If that's not the issue, double check that the function parameter types are exactly the same in the MsiScheduler.h declarations and MsiScheduler.cpp definitions, though they seem to be.
When you're compiling pingsrv.c you try to link msi with -l. Have you put libmsi.so in the library path so that -l can find it?
Consider the following:
// headher h.h
#pragma once
namespace foo {
const float c1 = 0.22;
inline float f() { return c1; }
const float c2 = f();
const float c3 = 0.33;
}
// source lib.cpp
#include "h.h"
Build a shared library with:
g++ -Wall -O2 -fPIC -shared -Wl,-soname,libme.so -o libme.so lib.cpp
The compiler (5.4.0) complains with:
h.h:9:13: warning: ‘foo::c2’ defined but not used [-Wunused-variable]
Why the warning? Don't they have external linkage?
Why only c2 ? There is no warning about c3.
Note that the warning goes away without optimization flags (-O0) (?!?)
(I know I could use constexpr, but in the real code I might have a non-literal type, so constexpr is no good)
EDIT:
Ok, consts in C++ have internal linkage (thanks Richard Critten). But my questions remain:
Why is there a warning about c2 and not about c3?
What is the "expected" compiler response? A warning or not? I would not expect any defined-but-not-used warning for constants in a header, that anyone could include to have access to them (so it makes not sense to warn a priori about no usage)
I try to compile this C++/Python library https://bitbucket.org/fluiddyn/fluidfft
If mpi4py is installed, it works well.
If mpi4py is not installed, code that does not use MPI cannot be compiled.
An error is raise during the compilation of a Cython file. The error is long and it starts by:
In file included from /usr/include/c++/6/bits/ios_base.h:46:0,
from /usr/include/c++/6/ios:42,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from src_cpp/base/base_fft.h:10,
from fluidfft/fft2d/fft2d_with_fftw1d.cpp:543:
/usr/include/c++/6/system_error:143:31: error: ‘error_category’ does not name a type
error_code(int __v, const error_category& __cat) noexcept
^~~~~~~~~~~~~~
/usr/include/c++/6/system_error:152:27: error: ‘error_category’ does not name a type
assign(int __v, const error_category& __cat) noexcept
^~~~~~~~~~~~~~
/usr/include/c++/6/system_error:172:11: error: ‘error_category’ does not name a type
const error_category&
^~~~~~~~~~~~~~
/usr/include/c++/6/system_error:191:11: error: ‘error_category’ does not name a type
const error_category* _M_cat;
[...]
I guess it could be a C++11 problem (http://en.cppreference.com/w/cpp/error/error_category) but I don't see how to solve the problem.
The compilation command is
g++ -pthread -fwrapv -O3 -Wall -Wno-unused-result -Wsign-compare -Wno-unused-result -Wsign-compare -fwrapv -O3 -Wall -fPIC -I/home/users/me/opt/miniconda3/include/python3.6m -I/home/users/me/opt/miniconda3/include -Isrc_cy -Ifluidfft/fft2d -Ifluidfft/fft3d -Isrc_cpp/base -Isrc_cpp/3d -Isrc_cpp/2d -Iinclude -I/home/users/me/opt/miniconda3/lib/python3.6/site-packages/numpy/core/include -c fluidfft/fft2d/fft2d_with_fftw1d.cpp -o build/temp.linux-x86_64-3.6/fluidfft/fft2d/fft2d_with_fftw1d.o
Edit Minimal, Complete, and Verifiable example
Thanks to Ashwin Vishnu (see https://bitbucket.org/fluiddyn/fluidfft/issues/7/fluidfft-installation-fails-without-mpi4py), I can post a minimal example
/* test.cpp */
#include <Python.h>
#include <string.h>
#include <stdio.h>
#include <cpu.h>
#include <sys/time.h>
#include <complex>
#include <iostream>
int main() {
std::cout<<"Hello world";
return 0;
}
compiled from fluidfft directory as follows:
g++ $(python-config --include) -Iinclude/ test.cpp
If we comment out cpu.h include, there are no errors.
The file cpu.h was taken from the pyfftw code: https://github.com/pyFFTW/pyFFTW/blob/master/include/cpu.h
This happens because the package fluidfft's Cython source files relied on a C++ header file cpu.h wherein the following preprocessor lines caused problems:
#if __STDC_VERSION__ >= 199901L
/* "inline" is a keyword */
#else
# define inline
#endif
My guess is the newer g++ compilers are strict on redefining reserved keywords. Following hints from an essay on inline functions, this block of code was replaced with:
#if __STDC_VERSION__ >= 199901L
/* "inline" is a keyword */
#else
# define INLINE
#endif
#ifndef INLINE
# if __GNUC__ && !__GNUC_STDC_INLINE__
# define INLINE static inline
# else
# define INLINE inline
# endif
#endif
I found an example where the output is different depending on the optimization settings (-O3 vs none), yet GCC 4.8.2 produces no warnings, even with the -std=c++11 -Wall -pedantic options.
In this particular case, I'm assuming that "forgetting" the commented line in header.h is a mistake, and with -O3, c<int>::get() gets inlined.
However, is there any way to protect yourself against these kinds of mistakes -- a compiler or linker option perhaps?
header.h:
#ifndef HEADER_H
#define HEADER_H
template<class T>
struct c
{
int get() { return 0; }
};
// template<> int c<int>::get();
#endif
imp.cpp:
#include "header.h"
template<>
int c<int>::get()
{
return 1;
}
main.cpp:
#include <iostream>
#include "header.h"
int main()
{
c<int> i;
std::cout << i.get() << '\n'; // prints 0 with -O3, and 1 without
}
build:
c++ -std=c++11 -pedantic -Wall -O3 -c imp.cpp
c++ -std=c++11 -pedantic -Wall -O3 -c main.cpp
c++ -std=c++11 -pedantic -Wall -O3 imp.o main.o
What you get if you have the line in your header-file, is a declaration of an explicit specialization for that member-function.
Thus, main.cpp is assured of a definition in some other compilation-unit, and things work.
If you leave it out, you have a violation of the ODR:
That specific instantiation of your class-template is different in the compilation-units. Resulting in "ill-formed, no diagnostic required", so anything goes.
And there is (currently?) no compiler-option to force gcc to diagnose it.
The true mistake here is the way you're laying out your source files and building them. When c<int>::get() is used, its definition should be available in order to instantiate the template. To fix this, header.h should #include "imp.cpp" rather than the other way around. You may want to rename imp.cpp to imp.inl or something else.
When you define templates which are used outside of a single .cpp file, those definitions should be visible to anyone who includes their header.
As an aside: I don't think there's any way to make the compiler or linker warn you about what you've done here. But if you structure your project as I've described, this problem won't happen, because the forward declaration will be unnecessary.
I have a header, core/types.hh, used by several different build targets. It has the following declaration:
core/types.hh
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
...
Some of the targets use this constant, some don't. So I get:
error: 'core::SZ_MAX' defined but not used"
I use scons with GCC 4.7.3 on Linux. I have -Wall set and want to keep it that way.
As far as I understand from the GCC documentation, this shouldn't give a warning:
-Wunused-variable
Warn whenever a local variable or non-constant static variable is unused aside from its declaration. This warning is enabled by -Wall.
So I don't see why I get a warning (which turns into an error).
On other answers, people were advised to make the declaration extern and to do the assignment in the file that uses the constant. This file is used by many other files, so it would loose its constant-ness if I do that. Furthermore, this file has header guards, so I think this should mean that the constant is actually created only once.
I'd appreciate any help!
Yuval
Possible duplicates:
How to use typed constants with “unused variable” warnings?
c++ static array declared in h file gives warning 'defined but not used'
It seems that this was not the error that halted compilation.
Rather, if GCC find another error, it would still report on this too.
I actually had another unused variable, and that's what caused this error in the first place.
For example, when creating the following files:
file1.cc
#include "head1.hh"
int main() {
int bad_unused_variable;
return my_ns::JUST_ANOTHER_CONST;
}
head1.hh
#ifndef HEAD1
#define HEAD1
#include <stdint.h>
#include <cstddef>
#include <limits>
namespace my_ns {
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
static const Size JUST_ANOTHER_CONST = 8;
}
#endif
You get:
> g++ -Wall -Werror file1.cc -O2 -std=c++98 -o file1
file1.cc: In function 'int main()':
file1.cc:4:6: error: unused variable 'bad_unused_variable' [-Werror=unused-variable]
In file included from file1.cc:1:0:
head1.hh: At global scope:
head1.hh:10:20: error: 'my_ns::SZ_MAX' defined but not used [-Werror=unused-variable]
cc1plus: all warnings being treated as errors
EDIT
This also seems to have been answered here: gcc warnings: defined but not used vs unused variable - there they mention the subtle differences between the two warning messages (unused variable vs defined but not used). Still, it doesn't really answer as to why GCC behaves this way...