[x265] [PATCH] cmake: export C API from multilib, enables multibit shared libs (fixes #153)

Steve Borho steve at borho.org
Mon Jul 6 21:03:10 CEST 2015


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1436209115 18000
#      Mon Jul 06 13:58:35 2015 -0500
# Node ID a19535d4306b482e68b616c95137335db2721530
# Parent  4a8af66739dbce6e1d7b54417de66b088e443835
cmake: export C API from multilib, enables multibit shared libs (fixes #153)

With these changes, one can add additional bit depths to any shared lib by
compiling the other bit depths with EXPORT_C_API=OFF and then linking those
libraries into the "default" build using EXTRA_LIB and then the appropriate
LINKED_??BIT cmake options. The default build does export the C API and thus
is a fully functional library even for applications which do not yet use the
introspection methods.

The batch files show an example of how to make an 8bit lib which includes 10 and
12bit libraries.

Note this also closes #154 since users should be building a single combined
shared lib which needs no additional link libraries specified in x265.pc

diff -r 4a8af66739db -r a19535d4306b build/linux/multilib.sh
--- a/build/linux/multilib.sh	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/linux/multilib.sh	Mon Jul 06 13:58:35 2015 -0500
@@ -13,5 +13,5 @@
 cd ../8bit
 ln -sf ../10bit/libx265.a libx265_main10.a
 ln -sf ../12bit/libx265.a libx265_main12.a
-cmake ../../../source -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265_main10.a;x265_main12.a" -DEXTRA_LINK_FLAGS=-L.
+cmake ../../../source -DEXTRA_LIB="x265_main10.a;x265_main12.a" -DEXTRA_LINK_FLAGS=-L. -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 make ${MAKEFLAGS}
diff -r 4a8af66739db -r a19535d4306b build/msys/multilib.sh
--- a/build/msys/multilib.sh	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/msys/multilib.sh	Mon Jul 06 13:58:35 2015 -0500
@@ -13,5 +13,5 @@
 cp libx265.a ../8bit/libx265_main10.a
 
 cd ../8bit
-cmake -G "MSYS Makefiles" ../../../source -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265_main10.a;x265_main12.a" -DEXTRA_LINK_FLAGS=-L.
+cmake -G "MSYS Makefiles" ../../../source -DEXTRA_LIB="x265_main10.a;x265_main12.a" -DEXTRA_LINK_FLAGS=-L. -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 make ${MAKEFLAGS}
diff -r 4a8af66739db -r a19535d4306b build/vc10-x86_64/multilib.bat
--- a/build/vc10-x86_64/multilib.bat	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/vc10-x86_64/multilib.bat	Mon Jul 06 13:58:35 2015 -0500
@@ -33,7 +33,7 @@
   msg "%username%" "12bit build failed"
   exit 1
 )
-cmake -G "Visual Studio 10 Win64" ../../../source -DHIGH_BIT_DEPTH=OFF -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib"
+cmake -G "Visual Studio 10 Win64" ../../../source -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib" -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 if exist x265.sln (
   MSBuild /property:Configuration="Release" x265.sln
 )
diff -r 4a8af66739db -r a19535d4306b build/vc11-x86_64/multilib.bat
--- a/build/vc11-x86_64/multilib.bat	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/vc11-x86_64/multilib.bat	Mon Jul 06 13:58:35 2015 -0500
@@ -33,7 +33,7 @@
   msg "%username%" "12bit build failed"
   exit 1
 )
-cmake -G "Visual Studio 11 Win64" ../../../source -DHIGH_BIT_DEPTH=OFF -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib"
+cmake -G "Visual Studio 11 Win64" ../../../source -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib" -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 if exist x265.sln (
   MSBuild /property:Configuration="Release" x265.sln
 )
diff -r 4a8af66739db -r a19535d4306b build/vc12-x86_64/multilib.bat
--- a/build/vc12-x86_64/multilib.bat	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/vc12-x86_64/multilib.bat	Mon Jul 06 13:58:35 2015 -0500
@@ -33,7 +33,7 @@
   msg "%username%" "12bit build failed"
   exit 1
 )
-cmake -G "Visual Studio 12 Win64" ../../../source -DHIGH_BIT_DEPTH=OFF -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib"
+cmake -G "Visual Studio 12 Win64" ../../../source -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib" -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 if exist x265.sln (
   MSBuild /property:Configuration="Release" x265.sln
 )
diff -r 4a8af66739db -r a19535d4306b build/vc9-x86_64/multilib.bat
--- a/build/vc9-x86_64/multilib.bat	Mon Jul 06 11:24:29 2015 -0500
+++ b/build/vc9-x86_64/multilib.bat	Mon Jul 06 13:58:35 2015 -0500
@@ -33,7 +33,7 @@
   msg "%username%" "12bit build failed"
   exit 1
 )
-cmake -G "Visual Studio 9 2008 Win64" ../../../source -DHIGH_BIT_DEPTH=OFF -DEXPORT_C_API=OFF -DENABLE_SHARED=OFF -DENABLE_CLI=ON -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib"
+cmake -G "Visual Studio 9 2008 Win64" ../../../source -DEXTRA_LIB="x265-static-main10.lib;x265-static-main12.lib" -DLINKED_10BIT=ON -DLINKED_12BIT=ON
 if exist x265.sln (
   MSBuild /property:Configuration="Release" x265.sln
 )
diff -r 4a8af66739db -r a19535d4306b doc/reST/api.rst
--- a/doc/reST/api.rst	Mon Jul 06 11:24:29 2015 -0500
+++ b/doc/reST/api.rst	Mon Jul 06 13:58:35 2015 -0500
@@ -365,9 +365,10 @@
 Multi-library Interface
 =======================
 
-If your application might want to make a runtime selection between a
-number of (static or dynamically linked) libx265 libraries, then you
-will want to use one of these bit-depth introspection interfaces.
+If your application might want to make a runtime bit-depth selection, it
+will need to use one of these bit-depth introspection interfaces which
+returns an API structure containing the public function entry points and
+constants.
 
 Instead of directly using all of the **x265_** methods documented above,
 you query an x265_api structure from your libx265 and then use the
@@ -452,62 +453,50 @@
 sizeof(x265_parm) and thereby ignore changes to that structure (which
 account for a large percentage of X265_BUILD bumps).
 
-Static Linking Implications
----------------------------
+Build Implications
+------------------
 
 By default libx265 will place all of its internal C++ classes and
 functions within an x265 namespace and export all of the C functions
 documented in this file. Obviously this prevents 8bit and 10bit builds
-of libx265 from being statically linked into a single application, all
-of those symbols would collide.
+of libx265 from being statically linked into a single binary, all of
+those symbols would collide.
 
-However, if you set the EXPORT_C_API cmake option to OFF, then libx265
-will use an x265_8bit or x265_10bit namespace for its C++ classes and
-functions (and use the same name as a prefix for its assembly functions)
-and only exports the two bit-depth introspection C functions from the
-8bit library and no C functions from the 10bit library. Thus
-applications which use one of the introspection functions (and no other
-exported C functions) may link with both 8bit and 10bit static libraries
-compiled with EXPORT_C_API=OFF.
+However, if you set the EXPORT_C_API cmake option to OFF then libx265
+will use a bit-depth specific namespace and prefix for its assembly
+functions (x265_8bit, x265_10bit or x265_12bit) and export no C
+functions.
+
+In this way you can build one or more libx265 libraries without any
+exported C interface and link them into libx265 build that does export a
+C interface. In this way, the build which exported the C functions
+becomes the *default* bit depth for the combined library, and the other
+bit depths are only available via the introspection methods.
 
 .. Note::
 
-	When libx265 is compiled with EXPORT_C_API=OFF, the two
-	bit-depth introspection functions will *not* attempt to dynamically
-	bind a shared library if the requested bit-depth is not found. It is
-	assuming that all necessary libraries will be statically linked.
+	When setting EXPORT_C_API cmake option to OFF, it is recommended to
+	also set ENABLE_SHARED and ENABLE_CLI to OFF to prevent build
+	problems.  We only need the static library from these builds.
 
-Dynamic Linking Implications
-----------------------------
+If an application requests a bit-depth that is not supported by the
+default library or any of the additionally linked libraries, the
+introspection method will fall-back to an attempt to dynamically bind a
+shared library with a name appropriate for the requested bit-depth::
 
-If your application is linking to a shared libx265 library, then again
-you have a choice of using the exported C functions or one of the
-bit-depth introspection functions. If your application uses the exported C
-functions, then it will always use the libx265 library which it links
-with.
-
-If instead your application uses one of the bit-depth introspection
-methods, your application may request the API for the bit-depth you
-would prefer to use (8 or 10). If the requested bit-depth is zero, or if
-it matches the bit-depth of the linked library, the linked library will
-be used for encode.  If you request a different bit-depth, the linked
-libx265 will attempt to dynamically bind a shared library with a name
-appropriate for the requested bit-depth::
-
-    8-bit:  libx265_main
-    10-bit: libx265_main10
-    12-bit: libx265_main12
+	8-bit:  libx265_main
+	10-bit: libx265_main10
+	12-bit: libx265_main12
 
 Packaging and Distribution
 --------------------------
 
-Packagers have a plethora of build choices for x265.
-
-For example on Windows, one could package together an x265.exe
-statically linked against the 8bit libx265 and a libx265_main10.dll in
-the same folder. This executable would be able to encode Main and Main10
-bitstreams. Or they may simply link the x265 CLI with both static
-libraries into a single executable file.
+We recommend that packagers distribute a single combined shared/static
+library build which includes all the bit depth libraries linked
+together. See the multilib scripts in our :file:`build/` subdirectories
+for examples of how to affect these combined library builds. It is the
+packager's discretion which bit-depth exports the public C functions and
+thus becomes the default bit-depth for the combined library.
 
 .. Note::
 
@@ -519,10 +508,3 @@
 
 	STATIC_LINK_CRT is also recommended so end-users will not need to
 	install any additional MSVC C runtime libraries.
-
-On Linux, x265 packagers could install 8bit static and shared libraries
-under the name libx265 (so all applications link against 8bit libx265)
-and then also install libx265_main10.so (symlinked to its numbered
-solib). Thus applications which use **x265_api_get()** or
-**x265_api_query()** will be able to select Main or Main10 encodes at
-runtime.
diff -r 4a8af66739db -r a19535d4306b source/CMakeLists.txt
--- a/source/CMakeLists.txt	Mon Jul 06 11:24:29 2015 -0500
+++ b/source/CMakeLists.txt	Mon Jul 06 13:58:35 2015 -0500
@@ -403,6 +403,9 @@
 if(NOT MSVC)
     set_target_properties(x265-static PROPERTIES OUTPUT_NAME x265)
 endif()
+if(EXTRA_LIB)
+    target_link_libraries(x265-static ${EXTRA_LIB})
+endif()
 if(EXTRA_LINK_FLAGS)
     list(APPEND LINKER_OPTIONS ${EXTRA_LINK_FLAGS})
 endif()
@@ -460,6 +463,9 @@
                 ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
                 RUNTIME DESTINATION ${BIN_INSTALL_DIR})
     endif()
+    if(EXTRA_LIB)
+        target_link_libraries(x265-shared ${EXTRA_LIB})
+    endif()
     if(LINKER_OPTIONS)
         # set_target_properties can't do list expansion
         string(REPLACE ";" " " LINKER_OPTION_STR "${LINKER_OPTIONS}")
@@ -534,9 +540,6 @@
         endif()
     endif()
     set_target_properties(cli PROPERTIES OUTPUT_NAME x265)
-    if(EXTRA_LIB)
-        target_link_libraries(cli ${EXTRA_LIB})
-    endif()
     if(LINKER_OPTIONS)
         # set_target_properties can't do list expansion
         string(REPLACE ";" " " LINKER_OPTION_STR "${LINKER_OPTIONS}")
diff -r 4a8af66739db -r a19535d4306b source/encoder/CMakeLists.txt
--- a/source/encoder/CMakeLists.txt	Mon Jul 06 11:24:29 2015 -0500
+++ b/source/encoder/CMakeLists.txt	Mon Jul 06 13:58:35 2015 -0500
@@ -11,6 +11,21 @@
    add_definitions(/wd4701) # potentially uninitialized local variable 'foo' used
 endif()
 
+if(EXTRA_LIB)
+    option(LINKED_8BIT  "8bit libx265 is being linked with this library" OFF)
+    option(LINKED_10BIT "10bit libx265 is being linked with this library" OFF)
+    option(LINKED_12BIT "12bit libx265 is being linked with this library" OFF)
+    if(LINKED_8BIT)
+        add_definitions(-DLINKED_8BIT=1)
+    endif(LINKED_8BIT)
+    if(LINKED_10BIT)
+        add_definitions(-DLINKED_10BIT=1)
+    endif(LINKED_10BIT)
+    if(LINKED_12BIT)
+        add_definitions(-DLINKED_12BIT=1)
+    endif(LINKED_12BIT)
+endif(EXTRA_LIB)
+
 add_library(encoder OBJECT ../x265.h
     analysis.cpp analysis.h
     search.cpp search.h
diff -r 4a8af66739db -r a19535d4306b source/encoder/api.cpp
--- a/source/encoder/api.cpp	Mon Jul 06 11:24:29 2015 -0500
+++ b/source/encoder/api.cpp	Mon Jul 06 13:58:35 2015 -0500
@@ -31,6 +31,28 @@
 #include "nal.h"
 #include "bitcost.h"
 
+/* multilib namespace reflectors */
+#if LINKED_8BIT
+namespace x265_8bit {
+const x265_api* x265_api_get(int bitDepth);
+const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err);
+}
+#endif
+
+#if LINKED_10BIT
+namespace x265_10bit {
+const x265_api* x265_api_get(int bitDepth);
+const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err);
+}
+#endif
+
+#if LINKED_12BIT
+namespace x265_12bit {
+const x265_api* x265_api_get(int bitDepth);
+const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err);
+}
+#endif
+
 #if EXPORT_C_API
 
 /* these functions are exported as C functions (default) */
@@ -322,6 +344,16 @@
 {
     if (bitDepth && bitDepth != X265_DEPTH)
     {
+#if LINKED_8BIT
+        if (bitDepth == 8) return x265_8bit::x265_api_get(0);
+#endif
+#if LINKED_10BIT
+        if (bitDepth == 10) return x265_10bit::x265_api_get(0);
+#endif
+#if LINKED_12BIT
+        if (bitDepth == 12) return x265_12bit::x265_api_get(0);
+#endif
+
         const char* libname = NULL;
         const char* method = "x265_api_get_" xstr(X265_BUILD);
 
@@ -375,8 +407,20 @@
         return NULL;
     }
 
+    if (err) *err = X265_API_QUERY_ERR_NONE;
+
     if (bitDepth && bitDepth != X265_DEPTH)
     {
+#if LINKED_8BIT
+        if (bitDepth == 8) return x265_8bit::x265_api_query(0, apiVersion, err);
+#endif
+#if LINKED_10BIT
+        if (bitDepth == 10) return x265_10bit::x265_api_query(0, apiVersion, err);
+#endif
+#if LINKED_12BIT
+        if (bitDepth == 12) return x265_12bit::x265_api_query(0, apiVersion, err);
+#endif
+
         const char* libname = NULL;
         const char* method = "x265_api_query";
 
@@ -426,48 +470,7 @@
         return api;
     }
 
-    if (err) *err = X265_API_QUERY_ERR_NONE;
     return &libapi;
 }
 
 } /* end namespace or extern "C" */
-
-
-/* multilib namespace reflectors */
-#if X265_DEPTH == 8 && !EXPORT_C_API
-
-namespace x265_10bit {
-const x265_api* x265_api_get(int bitDepth);
-const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err);
-}
-namespace x265_12bit {
-const x265_api* x265_api_get(int bitDepth);
-const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err);
-}
-
-extern "C"
-const x265_api* x265_api_get(int bitDepth)
-{
-    if (!bitDepth || bitDepth == 8)
-        return x265_8bit::x265_api_get(0);
-    else if (bitDepth == 10)
-        return x265_10bit::x265_api_get(0);
-    else if (bitDepth == 12)
-        return x265_12bit::x265_api_get(0);
-    return NULL;
-}
-
-extern "C"
-const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err)
-{
-    if (err) *err = X265_API_QUERY_ERR_NONE;
-    if (!bitDepth || bitDepth == 8)
-        return x265_8bit::x265_api_query(0, apiVersion, err);
-    else if (bitDepth == 10)
-        return x265_10bit::x265_api_query(0, apiVersion, err);
-    else if (bitDepth == 12)
-        return x265_12bit::x265_api_query(0, apiVersion, err);
-    if (err) *err = X265_API_QUERY_ERR_LIB_NOT_FOUND;
-    return NULL;
-}
-#endif


More information about the x265-devel mailing list