Skip to content

Commit

Permalink
feat: hide symbols for shared libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
zchrissirhcz committed Nov 23, 2024
1 parent ba97f7b commit afc51c0
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 104 deletions.
11 changes: 11 additions & 0 deletions rocbuild.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,16 @@ function(rocbuild_set_debug_postfix TARGET)
endfunction()


function(rocbuild_hide_symbols TARGET)
get_target_property(TARGET_TYPE ${TARGET} TYPE)
if(TARGET_TYPE STREQUAL "SHARED_LIBRARY")
if((CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") OR
(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang"))
target_compile_options(${TARGET} PRIVATE "-fvisibility=hidden")
endif()
endif()
endfunction()


rocbuild_set_artifacts_path()
rocbuild_enable_ninja_colorful_output()
255 changes: 151 additions & 104 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,111 +49,158 @@ def check_build(self, project_name, args=''):
self.assertEqual(0, ret, out)
return out.replace('\r\n', '\n')

def test_artifact_path(self):
if os_name == 'windows':
# determine if cl.exe is available
ret, out = check_output('cl')
if ret == 0:
self.check_generate('artifacts_path', args='-G "Ninja Multi-Config"')
self.check_build('artifacts_path', '--config Release')
self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe'))
shutil.rmtree('build/artifacts_path')

self.check_generate('artifacts_path', args="-G Ninja")
self.check_build('artifacts_path', '--config Release')
self.assertTrue(os.path.exists('build/artifacts_path/foo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/foo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/hello.exe'))
self.assertTrue(os.path.exists('build/artifacts_path/subfoo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/subfoo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/subhello.exe'))
shutil.rmtree('build/artifacts_path')

self.check_generate('artifacts_path')
self.check_build('artifacts_path', '--config Release')
self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll'))
self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe'))
elif os_name == 'linux':
self.check_generate('artifacts_path')
self.check_build('artifacts_path')
self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a'))
self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.so'))
self.assertTrue(os.path.exists('build/artifacts_path/hello'))
self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a'))
self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.so'))
self.assertTrue(os.path.exists('build/artifacts_path/subhello'))
# def test_artifact_path(self):
# if os_name == 'windows':
# # determine if cl.exe is available
# ret, out = check_output('cl')
# if ret == 0:
# self.check_generate('artifacts_path', args='-G "Ninja Multi-Config"')
# self.check_build('artifacts_path', '--config Release')
# self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe'))
# shutil.rmtree('build/artifacts_path')

# self.check_generate('artifacts_path', args="-G Ninja")
# self.check_build('artifacts_path', '--config Release')
# self.assertTrue(os.path.exists('build/artifacts_path/foo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/foo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/hello.exe'))
# self.assertTrue(os.path.exists('build/artifacts_path/subfoo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/subfoo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/subhello.exe'))
# shutil.rmtree('build/artifacts_path')

# self.check_generate('artifacts_path')
# self.check_build('artifacts_path', '--config Release')
# self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll'))
# self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe'))
# elif os_name == 'linux':
# self.check_generate('artifacts_path')
# self.check_build('artifacts_path')
# self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a'))
# self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.so'))
# self.assertTrue(os.path.exists('build/artifacts_path/hello'))
# self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a'))
# self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.so'))
# self.assertTrue(os.path.exists('build/artifacts_path/subhello'))
# elif os_name == 'mac':
# self.check_generate('artifacts_path')
# self.check_build('artifacts_path')
# self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a'))
# self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.dylib'))
# self.assertTrue(os.path.exists('build/artifacts_path/hello'))
# self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a'))
# self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.dylib'))
# self.assertTrue(os.path.exists('build/artifacts_path/subhello'))

# shutil.rmtree('build/artifacts_path')

# def test_debug_postfix(self):
# if os_name == 'windows':
# # msbuild
# self.check_generate('debug_postfix')
# self.check_build('debug_postfix', '--config Debug')
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib'))
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe'))
# shutil.rmtree('build/debug_postfix')

# ret, out = check_output('cl')
# if ret == 0:
# # ninja
# self.check_generate('debug_postfix', args='-G Ninja')
# self.check_build('debug_postfix')
# self.assertTrue(os.path.exists('build/debug_postfix/foo.lib'))
# self.assertTrue(os.path.exists('build/debug_postfix/hello.exe'))
# shutil.rmtree('build/debug_postfix')

# self.check_generate('debug_postfix', args='-G Ninja -DCMAKE_BUILD_TYPE=Debug')
# self.check_build('debug_postfix')
# self.assertTrue(os.path.exists('build/debug_postfix/foo.lib'))
# self.assertTrue(os.path.exists('build/debug_postfix/hello.exe'))
# shutil.rmtree('build/debug_postfix')

# # Ninja Multi-Config
# self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"')
# self.check_build('debug_postfix', '--config Debug')
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib'))
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe'))
# shutil.rmtree('build/debug_postfix')
# else:
# # Ninja Multi-Config
# self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"')
# self.check_build('debug_postfix')
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/libfoo_d.a'))
# self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d'))
# shutil.rmtree('build/debug_postfix')

# # make
# self.check_generate('debug_postfix')
# self.check_build('debug_postfix')
# self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a'))
# self.assertTrue(os.path.exists('build/debug_postfix/hello'))
# shutil.rmtree('build/debug_postfix')

# self.check_generate('debug_postfix', args='-DCMAKE_BUILD_TYPE=Debug')
# self.check_build('debug_postfix')
# self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a'))
# self.assertTrue(os.path.exists('build/debug_postfix/hello'))
# shutil.rmtree('build/debug_postfix')

def test_hide_symbols(self):
if os_name == 'linux':
self.check_generate('hide_symbols', args='-DHIDDEN=1')
self.check_build('hide_symbols')
cmd = 'nm -C build/hide_symbols/libbar.so | grep " T "'
ret, out = check_output(cmd)
self.assertEqual(0, ret, out)
out = out.replace('\r\n', '\n')
lines = out.strip().split('\n')
self.assertEqual(len(lines), 1, lines)
self.assertTrue(lines[0].endswith(' T bar'))
shutil.rmtree('build/hide_symbols')

self.check_generate('hide_symbols', args='-DHIDDEN=0')
self.check_build('hide_symbols')
cmd = f'nm -C build/hide_symbols/libbar.so | grep " T "'
ret, out = check_output(cmd)
self.assertEqual(0, ret, out)
out = out.replace('\r\n', '\n')
lines = out.strip().split('\n')
self.assertEqual(len(lines), 2, lines)
self.assertTrue(lines[0].endswith(' T bar'))
self.assertTrue(lines[1].endswith(' T bar_internal'))
shutil.rmtree('build/hide_symbols')
elif os_name == 'mac':
self.check_generate('artifacts_path')
self.check_build('artifacts_path')
self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a'))
self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.dylib'))
self.assertTrue(os.path.exists('build/artifacts_path/hello'))
self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a'))
self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.dylib'))
self.assertTrue(os.path.exists('build/artifacts_path/subhello'))

shutil.rmtree('build/artifacts_path')

def test_debug_postfix(self):
if os_name == 'windows':
# msbuild
self.check_generate('debug_postfix')
self.check_build('debug_postfix', '--config Debug')
self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib'))
self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe'))
shutil.rmtree('build/debug_postfix')

ret, out = check_output('cl')
if ret == 0:
# ninja
self.check_generate('debug_postfix', args='-G Ninja')
self.check_build('debug_postfix')
self.assertTrue(os.path.exists('build/debug_postfix/foo.lib'))
self.assertTrue(os.path.exists('build/debug_postfix/hello.exe'))
shutil.rmtree('build/debug_postfix')

self.check_generate('debug_postfix', args='-G Ninja -DCMAKE_BUILD_TYPE=Debug')
self.check_build('debug_postfix')
self.assertTrue(os.path.exists('build/debug_postfix/foo.lib'))
self.assertTrue(os.path.exists('build/debug_postfix/hello.exe'))
shutil.rmtree('build/debug_postfix')

# Ninja Multi-Config
self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"')
self.check_build('debug_postfix', '--config Debug')
self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib'))
self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe'))
shutil.rmtree('build/debug_postfix')
else:
# Ninja Multi-Config
self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"')
self.check_build('debug_postfix')
self.assertTrue(os.path.exists('build/debug_postfix/Debug/libfoo_d.a'))
self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d'))
shutil.rmtree('build/debug_postfix')

# make
self.check_generate('debug_postfix')
self.check_build('debug_postfix')
self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a'))
self.assertTrue(os.path.exists('build/debug_postfix/hello'))
shutil.rmtree('build/debug_postfix')

self.check_generate('debug_postfix', args='-DCMAKE_BUILD_TYPE=Debug')
self.check_build('debug_postfix')
self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a'))
self.assertTrue(os.path.exists('build/debug_postfix/hello'))
shutil.rmtree('build/debug_postfix')

self.check_generate('hide_symbols', args='-DHIDDEN=1')
self.check_build('hide_symbols')
cmd = 'nm -C build/hide_symbols/libbar.dylib | grep " T "'
ret, out = check_output(cmd)
self.assertEqual(0, ret, out)
out = out.replace('\r\n', '\n')
lines = out.strip().split('\n')
self.assertEqual(len(lines), 1, lines)
self.assertTrue(lines[0].endswith(' T _bar'))
shutil.rmtree('build/hide_symbols')

self.check_generate('hide_symbols', args='-DHIDDEN=0')
self.check_build('hide_symbols')
cmd = f'nm -C build/hide_symbols/libbar.dylib | grep " T "'
ret, out = check_output(cmd)
self.assertEqual(0, ret, out)
out = out.replace('\r\n', '\n')
lines = out.strip().split('\n')
self.assertEqual(len(lines), 2, lines)
self.assertTrue(lines[0].endswith(' T _bar'))
self.assertTrue(lines[1].endswith(' T _bar_internal'))
shutil.rmtree('build/hide_symbols')

if __name__ == "__main__":
unittest.main()
17 changes: 17 additions & 0 deletions tests/hide_symbols/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.10)
project(test_hide_symbols)

include(../../rocbuild.cmake)

add_library(bar SHARED
../src/bar.h
../src/bar.c
../src/bar_internal.h
../src/bar_internal.c
)
target_include_directories(bar PRIVATE ../src)
target_compile_definitions(bar PRIVATE BAR_EXPORTS)

if(HIDDEN)
rocbuild_hide_symbols(bar)
endif()
4 changes: 4 additions & 0 deletions tests/src/bar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "bar.h"
#include "bar_internal.h"

int bar() { return 1 + bar_internal(); }
25 changes: 25 additions & 0 deletions tests/src/bar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#ifdef BAR_EXPORTS
# if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)
# define BAR_API __declspec(dllexport)
# elif defined(__GNUC__) && __GNUC__ >= 4
# define BAR_API __attribute__ ((visibility ("default")))
# endif
#else
# if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)
# define BAR_API __declspec(dllimport)
# else
# define BAR_API
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

BAR_API int bar();

#ifdef __cplusplus
}
#endif
6 changes: 6 additions & 0 deletions tests/src/bar_internal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "bar_internal.h"

int bar_internal()
{
return 2;
}
11 changes: 11 additions & 0 deletions tests/src/bar_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

int bar_internal();

#ifdef __cplusplus
}
#endif

0 comments on commit afc51c0

Please sign in to comment.