Discussion:
A singleton based on the ACE_Singleton template class in a shared library is not exporting the ACE_Singleton::instance() method
(too old to reply)
Chuck Wanner
2017-12-08 21:30:21 UTC
Permalink
Hello,

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>;
public:

};

// 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)

When trying to perform the link to my executable, the following Link Error is generated:

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
Chuck Wanner
2017-12-13 22:21:12 UTC
Permalink
Post by Chuck Wanner
Hello,
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
Chuck Wanner
2017-12-14 20:39:42 UTC
Permalink
Post by Chuck Wanner
Hello,
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
A Minor Update to my last post. I forgot the -lTestSingleton on the command to build main.out. The updated command and output are below.

Command to build main.out:
g++ -L. -fPIC -Xlinker -rpath /usr/local/lib -Xlinker -rpath ./ -pthread main.o -lACE -lTestSingleton
main.o: In function `main':
/home/wanner/Templates/TestSingleton/main.cpp:11: undefined reference to `ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex>::instance()'
Chuck Wanner
2017-12-15 00:27:01 UTC
Permalink
Post by Chuck Wanner
Hello,
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
I performed another test. I removed the shared library from my test and linked testSingleton.o and main.o to create main.out. The results were the same using a shared library.

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 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 testSingleton.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()'

I think the fundamental issue with the first command, building the testSingleton.o object. Why is the command not generating the ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex> code? Any ideas would be appreciated.
Andreas Leitgeb
2017-12-15 10:03:21 UTC
Permalink
Post by Chuck Wanner
I performed another test. I removed the shared library from my test and linked testSingleton.o and main.o to create main.out. The results were the same using a shared library.
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
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
g++ -L. -fPIC -Xlinker -rpath /usr/local/lib -Xlinker -rpath ./ -pthread main.o testSingleton.o -lACE
/home/wanner/Templates/TestSingleton/main.cpp:11: undefined reference to `ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex>::instance()'
I think the fundamental issue with the first command, building the testSingleton.o object. Why is the command not generating the ACE_Singleton<testSingleton, ACE_Recursive_Thread_Mutex> code? Any ideas would be appreciated.
Another way to debug stuff is to let the preprocessor process a source
file and examine the output. usually, the option (to gcc/g++) for
merely preprocessing is "-E", (and the output is usually sent to stdout
so either redirect it to a file or pipe it to "less")

This preprocessing output might reveal what templates are defined
and/or instanciated.

On another thought, some compilers are "smart" and add certain symbols
to that particular ".o" file, that also contains the implementation of
the first method of the class that is actually supposed to have an
implementation (i.e. non-pure-virtual, non-inline)

In case your testclass contains methods that are declared, but not
implemented (even if not used, either), that could lead to similar
problems. (I know you posted your test class, but it was still too
long for me to scan through it and check if that is the case)
Chuck Wanner
2017-12-15 22:07:48 UTC
Permalink
Post by Chuck Wanner
Hello,
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
Andreas,

Using -E helped to solved my problem. I noticed extra code in the output of the UUID.cpp had but was not present in output my file. It appears that ACE Singletons with classes required a new (relative term, since I am porting from 5.8.2) macro to instantiate the singleton.

I found this macro at the end of the UUID.cpp:

ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_Singleton, ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX);

Once I started to add this macro for each of my singletons, my code was able to link with ACE 6.4.5.

Where is the best source of information to help with porting code to new versions of ACE?

Thank You,
Chuck Wanner
Johnny Willemsen
2017-12-16 19:05:48 UTC
Permalink
Hi,
Post by Chuck Wanner
Where is the best source of information to help with porting code to new versions of ACE?
The NEWS files in the ACE_wrappers and ACE_wrappers/TAO are a starting point.

Johnny Willemsen
http://www.remedy.nl

Loading...