Skip to content

Commit 5d2faa1

Browse files
committed
Interconnect: test emitting signals across shared object boundaries.
This worked "as is" a month ago when there was no -fvisibility-inlines-hidden, but that flag broke it. Now we need to explicitly export the inline functions as well. Added a verification test as well as additional docs explaining the situation.
1 parent a3d0ccc commit 5d2faa1

File tree

6 files changed

+212
-0
lines changed

6 files changed

+212
-0
lines changed

doc/corrade-changelog.dox

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ namespace Corrade {
169169
[mosra/corrade#53](https://github.com/mosra/corrade/issues/53))
170170
- The Emscripten CMake toolchain now sets the `EMSCRIPTEN` variable to help
171171
3rd party projects (see [mosra/toolchains#7](https://github.com/mosra/toolchains/pull/7))
172+
- Clarified interaction of `-fvisibility-inlines-hidden` and/or
173+
`-Wl,-Bsymbolic-functions` GCC/Clang flags and @ref Interconnect::Emitter
172174

173175
@subsection corrade-changelog-latest-bugfixes Bug fixes
174176

src/Corrade/Interconnect/Emitter.h

+38
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,44 @@ called from outside the class.
178178
179179
<b></b>
180180
181+
@m_class{m-block m-warning}
182+
183+
@par Connecting slots across shared objects
184+
If you're planning to use signal/slot connections across shared objects, be
185+
aware that in combination with GCC/Clang `-fvisibility-inlines-hidden`
186+
option (enabled by default when you use the `CORRADE_USE_PEDANTIC_FLAGS`
187+
@ref corrade-cmake "CMake property"), address of given signal inside a
188+
shared library will differ from its address outside of it. Copied from GCC
189+
documentation:
190+
@par
191+
<blockquote>
192+
This switch declares that the user does not attempt to compare pointers
193+
to inline methods where the addresses of the two functions were taken in
194+
different shared objects.
195+
</blockquote>
196+
@par
197+
There are three possible solutions:
198+
@par
199+
1. Compile without `-fvisibility-inlines-hidden`. Not recommended, as you
200+
usually have no control over externally specified flags. This flag is
201+
not available on MSVC or MinGW and while MSVC "just works", MinGW
202+
doesn't.
203+
2. Make the signal definition non-inline by moving its definition to a
204+
`*.cpp` file. Potentially very verbose, but works everywhere including
205+
MinGW.
206+
3. Annotating the function with an export macro such as
207+
@ref CORRADE_VISIBILITY_INLINE_MEMBER_EXPORT from
208+
@ref Corrade/Utility/VisibilityMacros.h that puts its visibility back
209+
to default. Doesn't work on MinGW either.
210+
@par
211+
Similar issue happens with the `-Wl,-Bsymbolic-functions` option passed to
212+
the linker. This flag is unfortunately present by default when building
213+
Ubuntu packages and has to be explicitly removed in order to make the
214+
signal connections work correctly. See the `package/debian/rules` file for
215+
an example how to do it.
216+
217+
<b></b>
218+
181219
@m_class{m-block m-danger}
182220
183221
@par MSVC and identical function merging

src/Corrade/Interconnect/Test/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ corrade_add_test(InterconnectTest Test.cpp LIBRARIES CorradeInterconnect)
2727
corrade_add_test(InterconnectStateMachineTest StateMachineTest.cpp LIBRARIES CorradeInterconnect)
2828
corrade_add_test(InterconnectBenchmark Benchmark.cpp LIBRARIES CorradeInterconnect)
2929

30+
add_library(InterconnectTestEmitterLibrary ${SHARED_OR_STATIC} EmitterLibrary.cpp)
31+
target_link_libraries(InterconnectTestEmitterLibrary PUBLIC CorradeInterconnect)
32+
corrade_add_test(InterconnectLibraryTest LibraryTest.cpp LIBRARIES CorradeInterconnect InterconnectTestEmitterLibrary)
33+
3034
set_target_properties(
3135
InterconnectTest
3236
InterconnectStateMachineTest
3337
InterconnectBenchmark
38+
InterconnectLibraryTest
3439
PROPERTIES FOLDER "Corrade/Interconnect/Test")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
This file is part of Corrade.
3+
4+
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
5+
2017, 2018, 2019 Vladimír Vondruš <[email protected]>
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a
8+
copy of this software and associated documentation files (the "Software"),
9+
to deal in the Software without restriction, including without limitation
10+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+
and/or sell copies of the Software, and to permit persons to whom the
12+
Software is furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included
15+
in all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
#include "EmitterLibrary.h"
27+
28+
namespace Corrade { namespace Interconnect { namespace Test {
29+
30+
void EmitterLibrary::fireInlineThroughAFunction() {
31+
fireInline();
32+
}
33+
34+
void EmitterLibrary::fireNonInlineThroughAFunction() {
35+
fireNonInline();
36+
}
37+
38+
auto EmitterLibrary::fireNonInline() -> Signal {
39+
return emit(&EmitterLibrary::fireNonInline);
40+
}
41+
42+
}}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#ifndef Corrade_Interconnect_Test_EmitterLibrary_h
2+
#define Corrade_Interconnect_Test_EmitterLibrary_h
3+
/*
4+
This file is part of Corrade.
5+
6+
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
7+
2017, 2018, 2019 Vladimír Vondruš <[email protected]>
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a
10+
copy of this software and associated documentation files (the "Software"),
11+
to deal in the Software without restriction, including without limitation
12+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
13+
and/or sell copies of the Software, and to permit persons to whom the
14+
Software is furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included
17+
in all copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25+
DEALINGS IN THE SOFTWARE.
26+
*/
27+
28+
#include "Corrade/Interconnect/Emitter.h"
29+
30+
#ifndef CORRADE_BUILD_STATIC
31+
#ifdef InterconnectTestEmitterLibrary_EXPORTS
32+
#define CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_EXPORT CORRADE_VISIBILITY_EXPORT
33+
#else
34+
#define CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_EXPORT CORRADE_VISIBILITY_IMPORT
35+
#endif
36+
#define CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_INLINE_MEMBER_EXPORT CORRADE_VISIBILITY_INLINE_MEMBER_EXPORT
37+
#else
38+
#define CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_EXPORT CORRADE_VISIBILITY_STATIC
39+
#define CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_INLINE_MEMBER_EXPORT CORRADE_VISIBILITY_STATIC
40+
#endif
41+
42+
namespace Corrade { namespace Interconnect { namespace Test {
43+
44+
struct CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_EXPORT EmitterLibrary: Emitter {
45+
void fireInlineThroughAFunction();
46+
void fireNonInlineThroughAFunction();
47+
48+
CORRADE_INTERCONNECT_TESTEMITTERLIBRARY_INLINE_MEMBER_EXPORT Signal fireInline() {
49+
return emit(&EmitterLibrary::fireInline);
50+
}
51+
52+
Signal fireNonInline();
53+
};
54+
55+
}}}
56+
57+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
This file is part of Corrade.
3+
4+
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
5+
2017, 2018, 2019 Vladimír Vondruš <[email protected]>
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a
8+
copy of this software and associated documentation files (the "Software"),
9+
to deal in the Software without restriction, including without limitation
10+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+
and/or sell copies of the Software, and to permit persons to whom the
12+
Software is furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included
15+
in all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
#include "Corrade/Interconnect/Test/EmitterLibrary.h"
27+
#include "Corrade/TestSuite/Tester.h"
28+
29+
namespace Corrade { namespace Interconnect { namespace Test { namespace {
30+
31+
struct LibraryTest: TestSuite::Tester {
32+
explicit LibraryTest();
33+
34+
void test();
35+
};
36+
37+
LibraryTest::LibraryTest() {
38+
addTests({&LibraryTest::test});
39+
}
40+
41+
void LibraryTest::test() {
42+
EmitterLibrary e;
43+
44+
int fired = 1;
45+
connect(e, &EmitterLibrary::fireInline, [&fired]() { fired *= 2; });
46+
connect(e, &EmitterLibrary::fireNonInline, [&fired]() { fired *= 3; });
47+
48+
e.fireNonInline();
49+
CORRADE_COMPARE(fired, 3);
50+
51+
e.fireInline();
52+
CORRADE_COMPARE(fired, 6);
53+
54+
e.fireNonInlineThroughAFunction();
55+
CORRADE_COMPARE(fired, 18);
56+
57+
{
58+
#ifdef __MINGW32__
59+
CORRADE_EXPECT_FAIL("Inline member functions are duplicated inside and outside of the DLL when under MinGW.");
60+
#endif
61+
e.fireInlineThroughAFunction();
62+
CORRADE_COMPARE(fired, 36);
63+
}
64+
}
65+
66+
}}}}
67+
68+
CORRADE_TEST_MAIN(Corrade::Interconnect::Test::LibraryTest)

0 commit comments

Comments
 (0)