diff options
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/ApiDsl.cmake | 44 | ||||
-rw-r--r-- | cmake/CompileGTest.cmake | 62 | ||||
-rw-r--r-- | cmake/Dependencies.cmake | 77 | ||||
-rw-r--r-- | cmake/MacRpath.cmake | 24 | ||||
-rw-r--r-- | cmake/ModulePackage.cmake | 143 | ||||
-rw-r--r-- | cmake/StrictAbi.cmake | 76 |
6 files changed, 426 insertions, 0 deletions
diff --git a/cmake/ApiDsl.cmake b/cmake/ApiDsl.cmake new file mode 100644 index 00000000..759f7f05 --- /dev/null +++ b/cmake/ApiDsl.cmake | |||
@@ -0,0 +1,44 @@ | |||
1 | ################################################################################ | ||
2 | # | ||
3 | # :: APIDSL regeneration | ||
4 | # | ||
5 | ################################################################################ | ||
6 | |||
7 | find_program(APIDSL NAMES | ||
8 | apidsl | ||
9 | apidsl.native | ||
10 | apidsl.byte | ||
11 | ${CMAKE_SOURCE_DIR}/../apidsl/apigen.native) | ||
12 | find_program(ASTYLE NAMES | ||
13 | astyle | ||
14 | $ENV{ASTYLE}) | ||
15 | |||
16 | function(apidsl) | ||
17 | if(APIDSL AND ASTYLE) | ||
18 | foreach(in_file ${ARGN}) | ||
19 | # Get the directory component of the input file name. | ||
20 | if(CMAKE_VERSION VERSION_LESS 3.0) | ||
21 | execute_process( | ||
22 | COMMAND dirname ${in_file} | ||
23 | OUTPUT_VARIABLE dirname | ||
24 | OUTPUT_STRIP_TRAILING_WHITESPACE) | ||
25 | else() | ||
26 | get_filename_component(dirname ${in_file} DIRECTORY) | ||
27 | endif() | ||
28 | |||
29 | # Get the name without extension (i.e. without ".api.h"). | ||
30 | get_filename_component(filename ${in_file} NAME_WE) | ||
31 | |||
32 | # Put them together, with the new extension that is ".h". | ||
33 | set(out_file ${CMAKE_SOURCE_DIR}/${dirname}/${filename}.h) | ||
34 | |||
35 | # Run apidsl. | ||
36 | add_custom_command( | ||
37 | OUTPUT ${out_file} | ||
38 | COMMAND "${APIDSL}" "${CMAKE_SOURCE_DIR}/${in_file}" | ||
39 | | "${ASTYLE}" --options="${CMAKE_SOURCE_DIR}/other/astyle/astylerc" | ||
40 | > "${out_file}" | ||
41 | DEPENDS ${in_file}) | ||
42 | endforeach() | ||
43 | endif() | ||
44 | endfunction() | ||
diff --git a/cmake/CompileGTest.cmake b/cmake/CompileGTest.cmake new file mode 100644 index 00000000..9aa4712f --- /dev/null +++ b/cmake/CompileGTest.cmake | |||
@@ -0,0 +1,62 @@ | |||
1 | # Find and compile the GTest library. | ||
2 | |||
3 | include(CheckCXXCompilerFlag) | ||
4 | include(CheckIncludeFileCXX) | ||
5 | |||
6 | message(STATUS "Checking for gtest") | ||
7 | |||
8 | # Look for the sources. | ||
9 | find_file(GTEST_ALL_CC gtest-all.cc PATHS | ||
10 | ${CMAKE_SOURCE_DIR}/third_party/googletest/googletest/src | ||
11 | /usr/src/gtest/src | ||
12 | NO_DEFAULT_PATH | ||
13 | ) | ||
14 | |||
15 | if(GTEST_ALL_CC) | ||
16 | # ../.. from the source file is the source root. | ||
17 | get_filename_component(GTEST_SRC_DIR ${GTEST_ALL_CC} DIRECTORY) | ||
18 | get_filename_component(GTEST_SRC_ROOT ${GTEST_SRC_DIR} DIRECTORY) | ||
19 | |||
20 | # Look for the header file. | ||
21 | include(CheckIncludeFileCXX) | ||
22 | include_directories(SYSTEM ${GTEST_SRC_ROOT}/include) | ||
23 | check_include_file_cxx("gtest/gtest.h" HAVE_GTEST_GTEST_H) | ||
24 | |||
25 | if(HAVE_GTEST_GTEST_H) | ||
26 | message(STATUS "Found gtest: ${GTEST_SRC_ROOT}") | ||
27 | |||
28 | add_library(gtest | ||
29 | ${GTEST_SRC_DIR}/gtest-all.cc | ||
30 | ${GTEST_SRC_DIR}/gtest_main.cc) | ||
31 | target_include_directories(gtest PRIVATE ${GTEST_SRC_ROOT}) | ||
32 | |||
33 | # Ignore all warnings for gtest. We don't care about their implementation. | ||
34 | check_cxx_compiler_flag("-w" HAVE_CXX_W QUIET) | ||
35 | if(HAVE_CXX_W) | ||
36 | set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w") | ||
37 | endif() | ||
38 | |||
39 | set(HAVE_GTEST TRUE) | ||
40 | set(TEST_CXX_FLAGS "") | ||
41 | |||
42 | check_cxx_compiler_flag("-Wno-global-constructors" HAVE_CXX_W_NO_GLOBAL_CONSTRUCTORS QUIET) | ||
43 | if(HAVE_CXX_W_NO_GLOBAL_CONSTRUCTORS) | ||
44 | set(TEST_CXX_FLAGS "${TEST_CXX_FLAGS} -Wno-global-constructors") | ||
45 | endif() | ||
46 | |||
47 | check_cxx_compiler_flag("-Wno-zero-as-null-pointer-constant" HAVE_CXX_W_NO_ZERO_AS_NULL_POINTER_CONSTANT QUIET) | ||
48 | if(HAVE_CXX_W_NO_ZERO_AS_NULL_POINTER_CONSTANT) | ||
49 | set(TEST_CXX_FLAGS "${TEST_CXX_FLAGS} -Wno-zero-as-null-pointer-constant") | ||
50 | endif() | ||
51 | endif() | ||
52 | endif() | ||
53 | |||
54 | function(unit_test subdir target) | ||
55 | if(HAVE_GTEST) | ||
56 | add_executable(unit_${target}_test ${subdir}/${target}_test.cc) | ||
57 | target_link_modules(unit_${target}_test toxcore gtest) | ||
58 | set_target_properties(unit_${target}_test PROPERTIES COMPILE_FLAGS "${TEST_CXX_FLAGS}") | ||
59 | add_test(NAME ${target} COMMAND ${CROSSCOMPILING_EMULATOR} unit_${target}_test) | ||
60 | set_property(TEST ${target} PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw") | ||
61 | endif() | ||
62 | endfunction() | ||
diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake new file mode 100644 index 00000000..5970fde7 --- /dev/null +++ b/cmake/Dependencies.cmake | |||
@@ -0,0 +1,77 @@ | |||
1 | ############################################################################### | ||
2 | # | ||
3 | # :: For UNIX-like systems that have pkg-config. | ||
4 | # | ||
5 | ############################################################################### | ||
6 | |||
7 | include(ModulePackage) | ||
8 | |||
9 | find_package(Threads REQUIRED) | ||
10 | |||
11 | find_library(NSL_LIBRARIES nsl ) | ||
12 | find_library(RT_LIBRARIES rt ) | ||
13 | find_library(SOCKET_LIBRARIES socket ) | ||
14 | |||
15 | # For toxcore. | ||
16 | pkg_use_module(LIBSODIUM libsodium ) | ||
17 | |||
18 | # For toxav. | ||
19 | pkg_use_module(OPUS opus ) | ||
20 | pkg_use_module(VPX vpx ) | ||
21 | |||
22 | # For tox-bootstrapd. | ||
23 | pkg_use_module(LIBCONFIG libconfig ) | ||
24 | |||
25 | # For tox-spectest. | ||
26 | pkg_use_module(MSGPACK msgpack ) | ||
27 | |||
28 | # For av_test. | ||
29 | pkg_use_module(OPENCV opencv ) | ||
30 | pkg_use_module(PORTAUDIO portaudio-2.0) | ||
31 | pkg_use_module(SNDFILE sndfile ) | ||
32 | |||
33 | ############################################################################### | ||
34 | # | ||
35 | # :: For MSVC Windows builds. | ||
36 | # | ||
37 | # These require specific installation paths of dependencies: | ||
38 | # - libsodium in third-party/libsodium/Win32/Release/v140/dynamic | ||
39 | # - pthreads in third-party/pthreads-win32/Pre-built.2 | ||
40 | # | ||
41 | ############################################################################### | ||
42 | |||
43 | if(MSVC) | ||
44 | # libsodium | ||
45 | # --------- | ||
46 | find_library(LIBSODIUM_LIBRARIES | ||
47 | NAMES sodium libsodium | ||
48 | PATHS | ||
49 | "third_party/libsodium/Win32/Release/v140/dynamic" | ||
50 | "third_party/libsodium/x64/Release/v140/dynamic" | ||
51 | ) | ||
52 | if(LIBSODIUM_LIBRARIES) | ||
53 | include_directories("third_party/libsodium/include") | ||
54 | set(LIBSODIUM_FOUND TRUE) | ||
55 | message("libsodium: ${LIBSODIUM_LIBRARIES}") | ||
56 | else() | ||
57 | message(FATAL_ERROR "libsodium libraries not found") | ||
58 | endif() | ||
59 | |||
60 | # pthreads | ||
61 | # -------- | ||
62 | if(CMAKE_USE_WIN32_THREADS_INIT) | ||
63 | find_library(CMAKE_THREAD_LIBS_INIT | ||
64 | NAMES pthreadVC2 | ||
65 | PATHS | ||
66 | "third_party/pthreads-win32/Pre-built.2/lib/x86" | ||
67 | "third_party/pthreads-win32/Pre-built.2/lib/x64" | ||
68 | ) | ||
69 | if(CMAKE_THREAD_LIBS_INIT) | ||
70 | include_directories("third_party/pthreads-win32/Pre-built.2/include") | ||
71 | add_definitions(-DHAVE_STRUCT_TIMESPEC) | ||
72 | message("libpthreads: ${CMAKE_THREAD_LIBS_INIT}") | ||
73 | else() | ||
74 | message(FATAL_ERROR "libpthreads libraries not found") | ||
75 | endif() | ||
76 | endif() | ||
77 | endif() | ||
diff --git a/cmake/MacRpath.cmake b/cmake/MacRpath.cmake new file mode 100644 index 00000000..ae5429dc --- /dev/null +++ b/cmake/MacRpath.cmake | |||
@@ -0,0 +1,24 @@ | |||
1 | # Taken from https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH. | ||
2 | # | ||
3 | # In many cases you will want to make sure that the required libraries are | ||
4 | # always found independent from LD_LIBRARY_PATH and the install location. Then | ||
5 | # you can use these settings: | ||
6 | |||
7 | # Use, i.e. don't skip the full RPATH for the build tree. | ||
8 | set(CMAKE_SKIP_BUILD_RPATH FALSE) | ||
9 | |||
10 | # When building, don't use the install RPATH already | ||
11 | # (but later on when installing). | ||
12 | set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) | ||
13 | |||
14 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") | ||
15 | |||
16 | # Add the automatically determined parts of the RPATH | ||
17 | # which point to directories outside the build tree to the install RPATH. | ||
18 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) | ||
19 | |||
20 | # The RPATH to be used when installing, but only if it's not a system directory. | ||
21 | list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) | ||
22 | if("${isSystemDir}" STREQUAL "-1") | ||
23 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") | ||
24 | endif() | ||
diff --git a/cmake/ModulePackage.cmake b/cmake/ModulePackage.cmake new file mode 100644 index 00000000..77911b1d --- /dev/null +++ b/cmake/ModulePackage.cmake | |||
@@ -0,0 +1,143 @@ | |||
1 | option(ENABLE_SHARED "Build shared (dynamic) libraries for all modules" ON) | ||
2 | option(ENABLE_STATIC "Build static libraries for all modules" ON) | ||
3 | |||
4 | if(NOT ENABLE_SHARED AND NOT ENABLE_STATIC) | ||
5 | message(WARNING | ||
6 | "Both static and shared libraries are disabled; " | ||
7 | "enabling only shared libraries. Use -DENABLE_SHARED or -DENABLE_STATIC to " | ||
8 | "select one manually.") | ||
9 | set(ENABLE_SHARED ON) | ||
10 | endif() | ||
11 | |||
12 | find_package(PkgConfig) | ||
13 | |||
14 | function(pkg_use_module mod pkg) | ||
15 | if(PKG_CONFIG_FOUND) | ||
16 | pkg_search_module(${mod} ${pkg}) | ||
17 | endif() | ||
18 | if(${mod}_FOUND) | ||
19 | link_directories(${${mod}_LIBRARY_DIRS}) | ||
20 | include_directories(${${mod}_INCLUDE_DIRS}) | ||
21 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${${mod}_CFLAGS_OTHER}" PARENT_SCOPE) | ||
22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${mod}_CFLAGS_OTHER}" PARENT_SCOPE) | ||
23 | |||
24 | foreach(dir ${${mod}_INCLUDE_DIRS}) | ||
25 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -isystem ${dir}" PARENT_SCOPE) | ||
26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${dir}" PARENT_SCOPE) | ||
27 | endforeach() | ||
28 | endif() | ||
29 | endfunction() | ||
30 | |||
31 | function(add_module lib) | ||
32 | set(${lib}_SOURCES ${ARGN} PARENT_SCOPE) | ||
33 | |||
34 | if(ENABLE_SHARED) | ||
35 | add_library(${lib}_shared SHARED ${ARGN}) | ||
36 | set_target_properties(${lib}_shared PROPERTIES OUTPUT_NAME ${lib}) | ||
37 | endif() | ||
38 | if(ENABLE_STATIC) | ||
39 | add_library(${lib}_static STATIC ${ARGN}) | ||
40 | set_target_properties(${lib}_static PROPERTIES OUTPUT_NAME ${lib}) | ||
41 | endif() | ||
42 | endfunction() | ||
43 | |||
44 | function(install_module lib) | ||
45 | if(ENABLE_SHARED) | ||
46 | set_target_properties(${lib}_shared PROPERTIES | ||
47 | VERSION ${SOVERSION} | ||
48 | SOVERSION ${SOVERSION_MAJOR} | ||
49 | ) | ||
50 | install(TARGETS ${lib}_shared | ||
51 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
52 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
53 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||
54 | endif() | ||
55 | if(ENABLE_STATIC) | ||
56 | install(TARGETS ${lib}_static | ||
57 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
58 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
59 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||
60 | endif() | ||
61 | |||
62 | string(REPLACE ";" " " ${lib}_PKGCONFIG_LIBS "${${lib}_PKGCONFIG_LIBS}") | ||
63 | string(REPLACE ";" " " ${lib}_PKGCONFIG_REQUIRES "${${lib}_PKGCONFIG_REQUIRES}") | ||
64 | |||
65 | configure_file( | ||
66 | "${${lib}_SOURCE_DIR}/other/pkgconfig/${lib}.pc.in" | ||
67 | "${CMAKE_BINARY_DIR}/${lib}.pc" | ||
68 | @ONLY | ||
69 | ) | ||
70 | |||
71 | configure_file( | ||
72 | "${toxcore_SOURCE_DIR}/other/rpm/${lib}.spec.in" | ||
73 | "${CMAKE_BINARY_DIR}/${lib}.spec" | ||
74 | @ONLY | ||
75 | ) | ||
76 | |||
77 | install(FILES | ||
78 | ${CMAKE_BINARY_DIR}/${lib}.pc | ||
79 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) | ||
80 | |||
81 | foreach(sublib ${${lib}_API_HEADERS}) | ||
82 | string(REPLACE "^" ";" sublib ${sublib}) | ||
83 | list(GET sublib 0 header) | ||
84 | |||
85 | install(FILES ${header} ${ARGN}) | ||
86 | endforeach() | ||
87 | endfunction() | ||
88 | |||
89 | function(target_link_modules target) | ||
90 | # If the target we're adding dependencies to is a shared library, add it to | ||
91 | # the set of targets. | ||
92 | if(TARGET ${target}_shared) | ||
93 | set(_targets ${_targets} ${target}_shared) | ||
94 | # Shared libraries should first try to link against other shared libraries. | ||
95 | set(${target}_shared_primary shared) | ||
96 | # If that fails (because the shared target doesn't exist), try linking | ||
97 | # against the static library. This requires the static library's objects to | ||
98 | # be PIC. | ||
99 | set(${target}_shared_secondary static) | ||
100 | endif() | ||
101 | # It can also be a static library at the same time. | ||
102 | if(TARGET ${target}_static) | ||
103 | set(_targets ${_targets} ${target}_static) | ||
104 | # Static libraries aren't actually linked, but their dependencies are | ||
105 | # recorded by "linking" them. If we link an executable to a static library, | ||
106 | # we want to also link statically against its transitive dependencies. | ||
107 | set(${target}_static_primary static) | ||
108 | # If a dependency doesn't exist as static library, we link against the | ||
109 | # shared one. | ||
110 | set(${target}_static_secondary shared) | ||
111 | endif() | ||
112 | # If it's neither, then it's an executable. | ||
113 | if(NOT _targets) | ||
114 | set(_targets ${_targets} ${target}) | ||
115 | # Executables preferably link against static libraries, so they are | ||
116 | # standalone and can be shipped without any external dependencies. As a | ||
117 | # frame of reference: tests become roughly 600-800K binaries instead of | ||
118 | # 50-100K on x86_64 Linux. | ||
119 | set(${target}_primary static) | ||
120 | set(${target}_secondary shared) | ||
121 | endif() | ||
122 | |||
123 | foreach(dep ${ARGN}) | ||
124 | foreach(_target ${_targets}) | ||
125 | if(TARGET ${dep}_${${_target}_primary}) | ||
126 | target_link_libraries(${_target} ${dep}_${${_target}_primary}) | ||
127 | elseif(TARGET ${dep}_${${_target}_secondary}) | ||
128 | target_link_libraries(${_target} ${dep}_${${_target}_secondary}) | ||
129 | else() | ||
130 | # We record the modules linked to this target, so that we can collect | ||
131 | # them later when linking a composed module. | ||
132 | list(FIND LINK_MODULES ${dep} _index) | ||
133 | if(_index EQUAL -1) | ||
134 | set(LINK_MODULES ${LINK_MODULES} ${dep}) | ||
135 | endif() | ||
136 | |||
137 | target_link_libraries(${_target} ${dep}) | ||
138 | endif() | ||
139 | endforeach() | ||
140 | endforeach() | ||
141 | |||
142 | set(${target}_LINK_MODULES ${${target}_LINK_MODULES} ${LINK_MODULES} PARENT_SCOPE) | ||
143 | endfunction() | ||
diff --git a/cmake/StrictAbi.cmake b/cmake/StrictAbi.cmake new file mode 100644 index 00000000..2dc5c5e0 --- /dev/null +++ b/cmake/StrictAbi.cmake | |||
@@ -0,0 +1,76 @@ | |||
1 | ################################################################################ | ||
2 | # | ||
3 | # :: Strict ABI | ||
4 | # | ||
5 | # Enabling the STRICT_ABI flag will generate and use an LD version script. | ||
6 | # It ensures that the dynamic libraries (libtoxcore.so, libtoxav.so) only | ||
7 | # export the symbols that are defined in their public API (tox.h and toxav.h, | ||
8 | # respectively). | ||
9 | # | ||
10 | ################################################################################ | ||
11 | |||
12 | find_program(SHELL NAMES sh dash bash zsh fish) | ||
13 | |||
14 | macro(make_version_script) | ||
15 | if(STRICT_ABI AND SHELL AND ENABLE_SHARED) | ||
16 | _make_version_script(${ARGN}) | ||
17 | endif() | ||
18 | endmacro() | ||
19 | |||
20 | function(_make_version_script target) | ||
21 | set(${target}_VERSION_SCRIPT "${CMAKE_BINARY_DIR}/${target}.ld") | ||
22 | |||
23 | file(WRITE ${${target}_VERSION_SCRIPT} | ||
24 | "{ global:\n") | ||
25 | |||
26 | foreach(sublib ${ARGN}) | ||
27 | string(REPLACE "^" ";" sublib ${sublib}) | ||
28 | list(GET sublib 0 header) | ||
29 | list(GET sublib 1 ns) | ||
30 | |||
31 | execute_process( | ||
32 | COMMAND ${SHELL} -c "egrep '^\\w' ${header} | grep '${ns}_[a-z0-9_]*(' | grep -v '^typedef' | grep -o '${ns}_[a-z0-9_]*(' | egrep -o '\\w+' | sort -u" | ||
33 | OUTPUT_VARIABLE sublib_SYMS | ||
34 | OUTPUT_STRIP_TRAILING_WHITESPACE) | ||
35 | string(REPLACE "\n" ";" sublib_SYMS ${sublib_SYMS}) | ||
36 | |||
37 | foreach(sym ${sublib_SYMS}) | ||
38 | file(APPEND ${${target}_VERSION_SCRIPT} | ||
39 | "${sym};\n") | ||
40 | endforeach(sym) | ||
41 | endforeach(sublib) | ||
42 | |||
43 | file(APPEND ${${target}_VERSION_SCRIPT} | ||
44 | "local: *; };\n") | ||
45 | |||
46 | set_target_properties(${target}_shared PROPERTIES | ||
47 | LINK_FLAGS -Wl,--version-script,${${target}_VERSION_SCRIPT}) | ||
48 | endfunction() | ||
49 | |||
50 | option(STRICT_ABI "Enforce strict ABI export in dynamic libraries" OFF) | ||
51 | if(WIN32 OR APPLE) | ||
52 | # Windows and OSX don't have this linker functionality. | ||
53 | set(STRICT_ABI OFF) | ||
54 | endif() | ||
55 | |||
56 | if(STRICT_ABI) | ||
57 | if(AUTOTEST) | ||
58 | message("AUTOTEST option is incompatible with STRICT_ABI. Disabling AUTOTEST.") | ||
59 | endif() | ||
60 | set(AUTOTEST OFF) | ||
61 | |||
62 | if(BUILD_MISC_TESTS) | ||
63 | message("BUILD_MISC_TESTS option is incompatible with STRICT_ABI. Disabling BUILD_MISC_TESTS.") | ||
64 | endif() | ||
65 | set(BUILD_MISC_TESTS OFF) | ||
66 | |||
67 | if(BOOTSTRAP_DAEMON) | ||
68 | message("BOOTSTRAP_DAEMON option is incompatible with STRICT_ABI. Disabling BOOTSTRAP_DAEMON.") | ||
69 | endif() | ||
70 | set(BOOTSTRAP_DAEMON OFF) | ||
71 | |||
72 | if(DHT_BOOTSTRAP) | ||
73 | message("DHT_BOOTSTRAP option is incompatible with STRICT_ABI. Disabling DHT_BOOTSTRAP.") | ||
74 | endif() | ||
75 | set(DHT_BOOTSTRAP OFF) | ||
76 | endif() | ||