Post by Chuck WannerHello,
I am trying to port software from using ACE 5.8.2 to ACE 6.4.5. We were using Redhat 5.4. We are now using CentOS 7.4. The software builds a few shared libraries and executable. Everything built until trying to link the executable.
One of my shared libraries declared a singleton using the ACE_Singleton Template.
class MyLib_Export MyClass {
friend class ACE_Singleton<MyClass, ACE_Recursive_Thread_Mutex>;
};
// define the macro MYCLIENT to point to our MyClass Singleton
typedef ACE_Singleton<MyClass, ACE_Recursive_Thread_Mutex> MyClassSingleton;
#define MYCLIENT MyClassSingleton::instance()
MYLIB_SINGLETON_DECLARE(ACE_Singleton, MyClass, ACE_Recursive_Thread_Mutex)
undefined reference to `ACE_Singleton<MyClass, ACE_Recursive_Thread_Mutex>::instance()'
I thought templates did not require to be exported, __attribute__((visibility(default))). The ACE Singleton template class does not have an export.
I did check the contents of the new generate_export_file.pl tool. The contents of the export file for the MyLib did not change.
I was hoping someone would recognize this error and know what I was doing wrong.
Thank You,
Chuck Wanner
Hello,
I have more information on my problem. Small sample code was generated to reproduce the problem.
Version 6.4.5 of the ACE Library is being used. I personally downloaded the ACE 6.4.5 tar ball, built, and installed the ACE library. The same compiler is being used for the test code.
The Linux Workstation is running CentOS Version 7.4.
cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
The GNU compiler is version 4.8.5.
g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
A testSingleton class was created that uses the ACE_Singleton class. The class was built as a shared library. I used the tool generate_export_file.pl to generate the export macros for the shared library. The main routine accesses the singleton class. When linking the main executable, the error “ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex>::instance is an undefined reference” is generated.
Here is the sample code that has the problem:
testSingleton.h:
#ifndef _TESTSINGLETON_H
#define _TESTSINGLETON_H
#include <ace/Singleton.h>
#include "testSingleton_export.h"
class TestSingleton_Export testSingleton
{
public:
testSingleton();
~testSingleton();
void hello(void);
};
typedef ACE_Singleton <testSingleton, ACE_Recursive_Thread_Mutex> TESTSINGLETON;
TESTSINGLETON_SINGLETON_DECLARE (ACE_Singleton, testSingleton, ACE_Recursive_Thread_Mutex)
#define SHORTCUT TESTSINGLETON::instance()
#endif /* _TESTSINGLETON_H */
testSingleton.cpp:
#include <stdio.h>
#include "testSingleton.h"
testSingleton::testSingleton()
{
}
testSingleton::~testSingleton()
{
}
void testSingleton::hello(void)
{
printf("Hello\n");
}
testSingleton_export.h:
// -*- C++ -*-
// Definition for Win32 Export directives.
// This file is generated automatically by generate_export_file.pl -d TestSingleton
// ------------------------------
#ifndef TESTSINGLETON_EXPORT_H
#define TESTSINGLETON_EXPORT_H
#include "ace/config-all.h"
#if defined (ACE_AS_STATIC_LIBS) && !defined (TESTSINGLETON_HAS_DLL)
# define TESTSINGLETON_HAS_DLL 0
#endif /* ACE_AS_STATIC_LIBS && TESTSINGLETON_HAS_DLL */
#if !defined (TESTSINGLETON_HAS_DLL)
# define TESTSINGLETON_HAS_DLL 1
#endif /* ! TESTSINGLETON_HAS_DLL */
#if defined (TESTSINGLETON_HAS_DLL) && (TESTSINGLETON_HAS_DLL == 1)
# if defined (TESTSINGLETON_BUILD_DLL)
# define TestSingleton_Export ACE_Proper_Export_Flag
# define TESTSINGLETON_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
# define TESTSINGLETON_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
# else /* TESTSINGLETON_BUILD_DLL */
# define TestSingleton_Export ACE_Proper_Import_Flag
# define TESTSINGLETON_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
# define TESTSINGLETON_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
# endif /* TESTSINGLETON_BUILD_DLL */
#else /* TESTSINGLETON_HAS_DLL == 1 */
# define TestSingleton_Export
# define TESTSINGLETON_SINGLETON_DECLARATION(T)
# define TESTSINGLETON_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
#endif /* TESTSINGLETON_HAS_DLL == 1 */
// Set TESTSINGLETON_NTRACE = 0 to turn on library specific tracing even if
// tracing is turned off for ACE.
#if !defined (TESTSINGLETON_NTRACE)
# if (ACE_NTRACE == 1)
# define TESTSINGLETON_NTRACE 1
# else /* (ACE_NTRACE == 1) */
# define TESTSINGLETON_NTRACE 0
# endif /* (ACE_NTRACE == 1) */
#endif /* !TESTSINGLETON_NTRACE */
#if (TESTSINGLETON_NTRACE == 1)
# define TESTSINGLETON_TRACE(X)
#else /* (TESTSINGLETON_NTRACE == 1) */
# if !defined (ACE_HAS_TRACE)
# define ACE_HAS_TRACE
# endif /* ACE_HAS_TRACE */
# define TESTSINGLETON_TRACE(X) ACE_TRACE_IMPL(X)
# include "ace/Trace.h"
#endif /* (TESTSINGLETON_NTRACE == 1) */
#endif /* TESTSINGLETON_EXPORT_H */
// End of auto generated file.
main.cpp:
#include <testSingleton.h>
int main(int argc, char** argv)
{
int temp = argc;
char ** temp_ptr = argv;
temp++;
temp_ptr++;
SHORTCUT->hello();
return 0;
}
I performed the following commands to build my source code:
Command to build testSingleton.o:
g++ -fvisibility=hidden -fvisibility-inlines-hidden -Wnon-virtual-dtor -O3 -ggdb -pthread -fno-strict-aliasing -Wall -W -Wpointer-arith -pipe -D_GNU_SOURCE -DTESTSINGLETON_BUILD_DLL -c -fPIC -o testSingleton.o testSingleton.cpp
Command to build libTestSingleton.so:
g++ -pthread -fPIC -shared -o libTestSingleton.so testSingleton.o -L/usr/local/lib -Wl,-R/usr/local/lib -Wl,--enable-new-dtags -ldl -lrt –lACE
Command to build main.o:
g++ -Wnon-virtual-dtor -O3 -ggdb -pthread -fno-strict-aliasing -Wall -W -Wpointer-arith -pipe -D_GNU_SOURCE -I. -fPIC -c -o main.o main.cpp
Command to build main.out:
g++ -L. -fPIC -Xlinker -rpath /usr/local/lib -Xlinker -rpath ./ -pthread main.o -lACE
main.o: In function `main':
/home/wanner/Templates/TestSingleton/main.cpp:11: undefined reference to `ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex>::instance()'
/home/wanner/Templates/TestSingleton/main.cpp:11: undefined reference to `testSingleton::hello()'
The test code is very similar the ACE_Utils::UUID_Generator class that uses the ACE Singleton class. Objdump was used to show the difference in the code generation. The UUID.o object has the ACE_Singleton code for the instance declared as part of the object. But the testSingleton.o object does not have any ACE_Singleton code for the instance of the ACE_Singleton declared.
The testSingleton.o is very small, so the complete symbol table was provided.
objdump -C -w -t testSingleton.o
testSingleton.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 testSingleton.cpp
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata.str1.1 0000000000000000 .rodata.str1.1
0000000000000000 l d .debug_info 0000000000000000 .debug_info
0000000000000000 l d .debug_abbrev 0000000000000000 .debug_abbrev
0000000000000000 l d .debug_loc 0000000000000000 .debug_loc
0000000000000000 l d .debug_aranges 0000000000000000 .debug_aranges
0000000000000000 l d .debug_line 0000000000000000 .debug_line
0000000000000000 l d .debug_str 0000000000000000 .debug_str
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l .rodata.str1.1 0000000000000000 .LC0
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 0000000000000002 testSingleton::testSingleton()
0000000000000000 g F .text 0000000000000002 testSingleton::testSingleton()
0000000000000010 g F .text 0000000000000002 testSingleton::~testSingleton()
0000000000000010 g F .text 0000000000000002 testSingleton::~testSingleton()
0000000000000020 g F .text 000000000000000c testSingleton::hello()
0000000000000000 *UND* 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000 *UND* 0000000000000000 puts
The objdump on the ACE UUID.o object. The UUID.o had large symbol table, so UUID’s symbol table was filtered on the symbol ACE_Singleton.
objdump -C -w -t .shobj/UUID.o | grep ACE_Singleton
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev
0000000000000000 l d .gcc_except_table._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev 0000000000000000 .gcc_except_table._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED0Ev 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED0Ev
0000000000000000 l d .gcc_except_table._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED0Ev 0000000000000000 .gcc_except_table._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED0Ev
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE4dumpEv 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE4dumpEv
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexEC2Ev 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexEC2Ev
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10instance_iEv 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10instance_iEv
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE7cleanupEPv 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE7cleanupEPv
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE5closeEv 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE5closeEv
0000000000000000 l d .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEv 0000000000000000 .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEv
0000000000000000 l d .bss._ZZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEvE4lock 0000000000000000 .bss._ZZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEvE4lock
0000000000000000 l d .rodata._ZTS13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000000 .rodata._ZTS13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE
0000000000000000 l d .data.rel.ro._ZTI13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000000 .data.rel.ro._ZTI13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE
0000000000000000 l d .data.rel.ro._ZTV13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000000 .data.rel.ro._ZTV13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE
0000000000000000 l d .bss._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10singleton_E 0000000000000000 .bss._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10singleton_E
0000000000000000 l .group 0000000000000000 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::~ACE_Singleton()
0000000000000000 l .group 0000000000000000 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::ACE_Singleton()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev 0000000000000042 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::~ACE_Singleton()
0000000000000000 w O .data.rel.ro._ZTV13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000028 vtable for ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED2Ev 0000000000000042 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::~ACE_Singleton()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexED0Ev 000000000000004a ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::~ACE_Singleton()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE4dumpEv 0000000000000002 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::dump()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexEC2Ev 000000000000003b ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::ACE_Singleton()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexEC2Ev 000000000000003b ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::ACE_Singleton()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10instance_iEv 0000000000000008 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::instance_i()
0000000000000000 u O .bss._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE10singleton_E 0000000000000008 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::singleton_
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE7cleanupEPv 0000000000000030 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::cleanup(void*)
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE5closeEv 000000000000002a ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::close()
0000000000000000 w F .text._ZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEv 0000000000000184 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::instance()
0000000000000000 u O .bss._ZZN13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE8instanceEvE4lock 0000000000000008 ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>::instance()::lock
0000000000000000 w O .rodata._ZTS13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000040 typeinfo name for ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>
0000000000000000 w O .data.rel.ro._ZTI13ACE_SingletonIN9ACE_Utils14UUID_GeneratorE16ACE_Thread_MutexE 0000000000000018 typeinfo for ACE_Singleton<ACE_Utils::UUID_Generator, ACE_Thread_Mutex>
I do not see what I am doing wrong. Why the compiler generated ACE_Singleton code for the UUID_Generator class, but not my class. Any ideas what I am doing wrong.
Thank You,
Chuck Wanner