I've implemented a variadic template function according to wiki. And iterate it with help of "overloading with "termination versions" of functions". The code:
void writeValue(QDataStream& /*data*/) {}
template<typename A, typename... Values>
void writeValue(QDataStream& data, const A& arg1, const Values&... args)
{
data << arg1;
writeValue(data, args...);
}
template<typename... Values>
quint32 PrepareMessage(QDataStream& data, func_code fcode, Values... parameters)
{
data << quint32(fcode);
writeValue(data, parameters...);
return 0;
}
It can be build and used without any problems with Qt 5.5 for Windows over MSVC2013 64bit toolchain.
Now I'm trying to build the same code on Linux with Qt 5.5 for Linux over GCC 64 bit and getting following errors at compilation:
g++ -c -pipe -std=c++11 -g -Wall -W -D_REENTRANT -fPIC -D_64bit -DQT_NETWORK_LIB -DQT_CORE_LIB -I../Trans2QuikWrapper -I. -I../../../Qt/5.5/gcc_64/include -I../../../Qt/5.5/gcc_64/include/QtNetwork -I../../../Qt/5.5/gcc_64/include/QtCore -I. -I../../../Qt/5.5/gcc_64/mkspecs/linux-g++ -o moc_T2Q_Client.o moc_T2Q_Client.cpp
g++ -Wl,-rpath,/home/truf/Qt/5.5/gcc_64 -Wl,-rpath,/home/truf/Qt/5.5/gcc_64/lib -o t2q T2Q_Client.o main_client.o moc_T2Q_Client.o -L/home/truf/Qt/5.5/gcc_64/lib -lQt5Network -lQt5Core -lpthread
main_client.o: In function `int QGenericAtomicOps<QBasicAtomicOps<4> >::load<int>(int const&)':
/home/truf/.wine/drive_c/build-t2q-Desktop_Qt_5_5_1_GCC_64bit-Debug/../Trans2QuikWrapper/io_utils.h:16: multiple definition of `writeValue(QDataStream&)'
Makefile:192: recipe for target 't2q' failed
T2Q_Client.o:/home/truf/.wine/drive_c/build-t2q-Desktop_Qt_5_5_1_GCC_64bit-Debug/../Trans2QuikWrapper/io_utils.h:16: first defined here
moc_T2Q_Client.o: In function `int QGenericAtomicOps<QBasicAtomicOps<4> >::load<int>(int const&)':
/home/truf/.wine/drive_c/build-t2q-Desktop_Qt_5_5_1_GCC_64bit-Debug/../Trans2QuikWrapper/io_utils.h:16: multiple definition of `writeValue(QDataStream&)'
T2Q_Client.o:/home/truf/.wine/drive_c/build-t2q-Desktop_Qt_5_5_1_GCC_64bit-Debug/../Trans2QuikWrapper/io_utils.h:16: first defined here
collect2: error: ld returned 1 exit status
make: *** [t2q] Error 1
gcc version is 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2). Wine is not involved - just a folder location.
Are variadic templates supported there? Any additional compilation parameters needed? Or roblem is in code?
The error message says:
multiple definition of `writeValue(QDataStream&)'
To solve this, you must declare writeValue() as inline:
inline void writeValue(QDataStream& /*data*/) {}
When you define a function in a header file, you always should mark it as inline. This way, it won't break the ODR if you include the header in multiple translation units.
Related
I have a C++ dynamic library (on macOS) that has a templated function with some explicit instantiations that are exported in the public API. Client code only sees the template declaration; they have no idea what goes on inside it and are relying on these instantiations to be available at link time.
For some reason, only some of these explicit instantiations are made visible in the dynamic library.
Here is a simple example:
// libtest.cpp
#define VISIBLE __attribute__((visibility("default")))
template<typename T> T foobar(T arg) {
return arg;
}
template int VISIBLE foobar(int);
template int* VISIBLE foobar(int*);
I would expect both instantiations to be visible, but only the non-pointer one is:
$ clang++ -dynamiclib -O2 -Wall -Wextra -std=c++1z -stdlib=libc++ -fvisibility=hidden -fPIC libtest.cpp -o libtest.dylib
$ nm -gU libtest.dylib | c++filt
0000000000000f90 T int foobar<int>(int)
This test program fails to link because the pointer one is missing:
// client.cpp
template<typename T> T foobar(T); // assume this was in the library header
int main() {
foobar<int>(1);
foobar<int*>(nullptr);
return 0;
}
$ clang++ -O2 -Wall -Wextra -std=c++1z -stdlib=libc++ -L. -ltest client.cpp -o client
Undefined symbols for architecture x86_64:
"int* foobar<int*>(int*)", referenced from:
_main in client-e4fe7d.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
There does seem to be some connection between the types and the visibility. If I change the return type to void, they are all visible (even if the template arguments are still pointers or whatever). Especially bizarre, this exports both:
template auto VISIBLE foobar(int) -> int;
template auto VISIBLE foobar(int*) -> int*;
Is this a bug? Why would apparent syntactic sugar change behavior?
It works if I change the template definition to be visible, but it seems non-ideal because only a few of these instantiations should be exported... and I still want to understand why this is happening, either way.
I am using Apple LLVM version 8.0.0 (clang-800.0.42.1).
Your problem is reproducible on linux:
$ clang++ --version
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden \
-fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000620 W int foobar<int>(int)
0000000000000630 t int* foobar<int*>(int*)
The non-pointer overload is weakly global but the pointer overload is
local.
The cause of this is obscured by clang's slack diagnosing of the __attribute__
syntax extension, which after all is a GCC invention. If we compile with
g++ instead we get:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
libtest.cpp:9:36: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
template int * VISIBLE foobar(int *);
^
Notice that g++ ignores the visibility attribute only in the pointer overload,
and, just like clang - and consistent with that warning - it emits code with:
$ nm -C libtest.so | grep foobar
0000000000000610 W int foobar<int>(int)
0000000000000620 t int* foobar<int*>(int*)
Clearly clang is doing the same thing, but not telling us why.
The difference between the overloads that satisfies g++ with one and
dissatisfies it with the other is the difference between int and int *.
On that basis we'd expect g++ to be satisfied with the change:
template int VISIBLE foobar(int);
//template int * VISIBLE foobar(int *);
template float VISIBLE foobar(float);
And so it is:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000650 W float foobar<float>(float)
0000000000000640 W int foobar<int>(int)
And so is clang:
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000660 W float foobar<float>(float)
0000000000000650 W int foobar<int>(int)
Both of them will do what you want for overloads with T a non-pointer type, but
not with T a pointer type.
What you face here, however, is not a ban on dynamically visible functions
that return pointers rather than non-pointers. It couldn't have escaped notice if
visibility was as broken as that. It is just a ban on types of the form:
D __attribute__((visibility("...")))
where D is a pointer or reference type, as distinct from types of the form:
E __attribute__((visibility("..."))) *
or:
E __attribute__((visibility("..."))) &
where E is not a pointer or reference type. The distinction is between:
A (pointer or reference that has visibility ...) to type D
and:
A (pointer or reference to type E) that has visibility ...
See:
$ cat demo.cpp
int xx ;
int __attribute__((visibility("default"))) * pvxx; // OK
int * __attribute__((visibility("default"))) vpxx; // Not OK
int __attribute__((visibility("default"))) & rvxx = xx; // OK,
int & __attribute__((visibility("default"))) vrxx = xx; // Not OK
$ g++ -shared -Wall -Wextra -std=c++1z -fvisibility=hidden -o libdemo.so demo.cpp
demo.cpp:3:46: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
int * __attribute__((visibility("default"))) vpxx; // Not OK
^
demo.cpp:5:46: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
int & __attribute__((visibility("default"))) vrxx = xx; // Not OK
^
$ nm -C libdemo.so | grep xx
0000000000201030 B pvxx
0000000000000620 R rvxx
0000000000201038 b vpxx
0000000000000628 r vrxx
0000000000201028 b xx
The OK declarations become global symbols; the Not OK ones become local,
and only the former are dynamically visible:
nm -CD libdemo.so | grep xx
0000000000201030 B pvxx
0000000000000620 R rvxx
This behaviour is reasonable. We can't expect a compiler to attribute
global, dynamic visibility to a pointer or reference that could point or
refer to something that does not have global or dynamic visibility.
This reasonable behaviour only appears to frustrate your objective because
- as you probably now see:
template int VISIBLE foobar(int);
template int* VISIBLE foobar(int*);
doesn't mean what you thought it did. You thought that, for given type U,
template U VISIBLE foobar(U);
declares a template instantiating function that has default
visibility, accepting an argument of type U and returning the same. In fact,
it declares a template instantiating function that accepts an argument of
type U and returns type:
U __attribute__((visibility("default")))
which is allowed for U = int, but disallowed for U = int *.
To express your intention that instantations of template<typename T> T foobar(T arg)
shall be dynamically visible functions, qualify the type of the template function
itself with the visibility attribute. Per GCC's documentation of the __attribute__
syntax - which admittedly
says nothing specific concerning templates - you must make an attribute
qualification of a function in a declaration other than its definition. So complying
with that, you'd revise your code like:
// libtest.cpp
#define VISIBLE __attribute__((visibility("default")))
template<typename T> T foobar(T arg) VISIBLE;
template<typename T> T foobar(T arg) {
return arg;
}
template int foobar(int);
template int* foobar(int*);
g++ no longer has any gripes:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -CD libtest.so | grep foobar
0000000000000640 W int foobar<int>(int)
0000000000000650 W int* foobar<int*>(int*)
and both of the overloads are dynamically visible. The same goes for clang:
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -CD libtest.so | grep foobar
0000000000000650 W int foobar<int>(int)
0000000000000660 W int* foobar<int*>(int*)
With any luck, you'll have the same result with clang on Mac OS
#include <iostream>
struct CL1
{
virtual void fnc1();
virtual void fnc2(); //not defined anywhere
};
void CL1::fnc1(){}
int main() {}
This gives an undefined reference error on fnc2, however it isn't used anywhere. Why is this happening? I tried to do it on Visual Studio and then it's linked successfully.
gcc does not remove not used symbols by default at link time,
so for your class with virtual functions, it generate virtual table,
with pointers to each virtual function, and move this table to .rodata section,
so you should receive such error message:
g++ test10.cpp
/tmp/cc5YTcBb.o:(.rodata._ZTV3CL1[_ZTV3CL1]+0x18): undefined reference to `CL1::fnc2()'
collect2: error: ld returned 1 exit status
You can enable garbage collection and link time, and you not receive
and errors:
$ g++ -O3 -O3 -fdata-sections -ffunction-sections -fipa-pta test10.cpp -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed
$
I've been trying to compile with std::atomic, and I'm getting unresolved references to __atomic_load, __atomic_store, and __atomic_store_16.
I know in a later version of gcc (4.8+?) you include -latomic, but I'm compiling with gcc 4.7.3; I've tried adding -latomic_ops and -latomic_ops_gpl, but neither seem to do much.
I am installing gcc 4.8.1 now, but I do have a release platform that'll really need to be compiled for 4.7.3.
Many thanks.
Edit:
Ok, here's some code that results in the problem I have:
atomics.cpp
#include <atomic>
#include <stdint.h>
struct dataStruct {
int a;
uint16_t b;
float c;
dataStruct(int ai, uint16_t bi, float ci) noexcept : a(ai), b(bi), c(ci) {
}
dataStruct() noexcept : dataStruct(0,0,0) {
}
};
int main() {
std::atomic<dataStruct> atomicValue;
atomicValue = dataStruct(10, 0, 0);
return atomicValue.load().b;
}
With "g++-4.8.1 *.cpp -std=c++0x -latomic", this compiles fine.
With "g++-4.7.3 *.cpp -std=c++0x -pthread -lpthread -latomic_ops", it fails with the following:
/tmp/ccQp8MJ2.o: In function `std::atomic<dataStruct>::load(std::memory_order) const':
atomics.cpp:(.text._ZNKSt6atomicI10dataStructE4loadESt12memory_order[_ZNKSt6atomicI10dataStructE4loadESt12memory_order]+0x2f): undefined reference to `__atomic_load'
/tmp/ccQp8MJ2.o: In function `std::atomic<dataStruct>::store(dataStruct, std::memory_order)':
atomics.cpp:(.text._ZNSt6atomicI10dataStructE5storeES0_St12memory_order[_ZNSt6atomicI10dataStructE5storeES0_St12memory_order]+0x35): undefined reference to `__atomic_store'
collect2: error: ld returned 1 exit status
Ok, finally found the answer at: https://gcc.gnu.org/wiki/Atomic/GCCMM
Turns out, 4.7 did not in fact have 'official' atomics support (just the header files). If you want to use atomics in 4.7 compilers, you must download the source code linked on that page and build it yourself
gcc -c -o libatomic.o libatomic.c
ar rcs libatomic.a libatomic.o
Then, you can build it using
g++-4.7.3 -std=c++0x atomics.cpp -latomic -L./
As firefox 12 sdk removed the 'Proxy' object, I wanted to use cross-thread calls using nsRunnable. I basically did copy-and paste of the code:
class NotifyTask : public nsRunnable
{
public:
NotifyTask(nsISupports *subject, const char *topic, bool remref)
: mWorkerThread(do_GetCurrentThread())
{
MOZ_ASSERT(!NS_IsMainThread()); // This should be running on the worker thread
}
NS_IMETHOD Run() {
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main thread!
mWorkerThread->Shutdown();
return NS_OK;
}
private:
nsCOMPtr<nsIThread> mWorkerThread;
};
And I tried to compile it. I got following errors:
g++ -std=gnu++0x -Wall -O2 -c -DUSE_LIBUSB -fPIC -DHAVE_CRYPTO -fpermissive -DCRYPTPP -fshort-wchar -I../../xulrunner-sdk/include -o gipsy.o gipsy.cpp
gipsy.cpp:74:7: warning: ‘NotifyTask’ declared with greater visibility than the type of its field ‘NotifyTask::<anonymous>’ [-Wattributes]
gipsy.cpp:74:7: warning: ‘NotifyTask’ declared with greater visibility than its base ‘nsRunnable’ [-Wattributes]
g++ -std=gnu++0x -Wl,-z,defs -Wall -Os -o gipsy.so -shared gipsy.o gipsymodule.o tracklog.o gpslib/data.o gpslib/garmin.o gpslib/gps.o gpslib/phys.o gpslib/igc.o gpslib/aircotec.o cp1250.o prefparser.o gpslib/foreignigc.o gpslib/mlr.o gpslib/flymaster.o gpslib/compeo.o gpslib/iq.o ../libs/libcryptopp.a -lusb -L../../xulrunner-sdk/lib -lxpcomglue_s -lxul -lxpcom -lplds4 -lplc4 -lnspr4 -lpthread -ldl -lmozalloc
gipsy.o:(.data.rel.ro._ZTI10NotifyTask[typeinfo for NotifyTask]+0x10): undefined reference to `typeinfo for nsRunnable'
collect2: ld returned 1 exit status
According to g++ undefined reference to typeinfo it might be that gecko sdk was built with -fvisibility=hidden and some weird 'key method in different .so'. Is this an error in Gecko sdk or am I doing something wrong?
The gecko SDK is not link with RTTI - adding "-fno-rtti" parameter to the particular .o file fixed the problem.
Suppose we have the following code:
#if !defined(__cplusplus)
# error This file should be compiled as C++
#endif
#include <stdio.h>
#include <string>
//#define USE_CXX_CLASS
#ifdef USE_CXX_CLASS
class SomeClass
{
public:
SomeClass() {}
~SomeClass() {}
std::string GetSomeString()
{
// case #1
}
};
#endif // USE_CXX_CLASS
int foo()
{
// case #2
}
int
main (int argc, char *argv[])
{
(void)argc;
(void)argv;
#ifdef USE_CXX_CLASS
SomeClass someInstance;
someInstance.GetSomeString();
#endif // USE_CXX_CLASS
foo();
return 0;
}
And suppose that it were to be compiled the C++ compiler (and not the C compiler) from GCC version 4.2.1 with the options -Wreturn-type -Werror=return-type. If the above code is compiled as is without first uncommenting the //#define USE_CXX_CLASS line above, then you will see a warning but no error:
.../gcc-4.2.1/bin/g++ -g -fPIC -Wreturn-type -Werror=return-type test.cpp -c -o test.o
test.cpp: In function 'int foo()':
test.cpp:26: warning: control reaches end of non-void function
But if the //#define USE_CXX_CLASS line is uncommented, then the warning is treated as an error:
.../gcc-4.2.1/bin/g++ -g -fPIC -Wreturn-type -Werror=return-type test.cpp -c -o test.o
test.cpp: In member function 'std::string SomeClass::GetSomeString()':
test.cpp:18: error: no return statement in function returning non-void [-Wreturn-type]
gmake: *** [test.o] Error 1
Yes, one is a non-member function (case #2), and the other is a C++ function (case #1). IMO, that should not matter. I want both conditions treated as an error, and I don't want to add -Werror or -Wall at this point in time (probably will do so later, but that is out of scope of this question).
My sub-questions are:
Is there some GCC switch that I am missing that should work? (No I do not want to use #pragma's.)
Is this a bug that has been addressed in a more recent version of GCC?
For reference, I have already poured through other similar questions already, including the following:
Why does flowing off the end of a non-void function without returning a value not produce a compiler error?
C question: no warning?
Is a return statement mandatory for C++ functions that do not return void?
It has been fixed, it works well with g++ 9.3: both member functions and free functions are treated as error with -Wall -Werror=return-type
I do see an error even w/o the USE_CXX_CLASS flag. i.e. g++ is consistent with the error for both class member functions and non member functions.
g++ (GCC) 4.4.3 20100127 (Red Hat 4.4.3-4)
It seems to me that what you need is a shell script wrapper around gcc.
Name it something like gcc-wrapper and g++-wrapper.
In your Makefile set CC and CXX to the wrappers.
Have the wrapper invoke GCC and pipe its output to another program which will search for your desired warning strings.
Have the search program exit with an error when it finds the warning.