Single library with both shared and static binaries

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Single library with both shared and static binaries

Avraham Shukron
Hi!

I have a library which I want to distribute in both shared object and static library forms.
Is there a modern way to do it without creating two completely separate library targets?
Since I want to be a good CMake citizen I use `target_*` and `set_target_properties` as much as possible, and creating two different libraries will force me to duplicate that information about each one of them.

I also tries not specifying STATIC/SHARED, and then running cmake twice - once with BUILD_SHARED_LIBS=ON and once OFF and then installing to the same directory. I got my both .a and .so libraries installed, but I couldn't get the Config file correctly for this arrangement.

So - what is the community-recommended pattern to do this?

Thanks,
Avi.

--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Single library with both shared and static binaries

CMake mailing list
On Tue, 2019-09-24 at 23:41 +0300, Avraham Shukron wrote:

> Hi!
>
> I have a library which I want to distribute in both shared object and
> static library forms.
> Is there a modern way to do it without creating two completely
> separate library targets?
> Since I want to be a good CMake citizen I use `target_*` and
> `set_target_properties` as much as possible, and creating two
> different libraries will force me to duplicate that information about
> each one of them.
>
> I also tries not specifying STATIC/SHARED, and then running cmake
> twice - once with BUILD_SHARED_LIBS=ON and once OFF and then
> installing to the same directory. I got my both .a and .so libraries
> installed, but I couldn't get the Config file correctly for this
> arrangement.
>
> So - what is the community-recommended pattern to do this?

Unfortunately, the recommendation is to do exactly what you don't want
to do: create a shared target and a static target.

To make this slightly simpler, you can use functions to de-duplicate
the target_* and set_target_properties calls:

function(create_foo_target name type)
  add_library(${name} ${type} foo.c foo.h)
  set_target_properties(${name} OUTPUT_NAME foo)
endfunction()

create_foo_target(foo_shared SHARED)
create_foo_target(foo_static STATIC)

Kyle
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Single library with both shared and static binaries

Simon Richter
In reply to this post by Avraham Shukron
Hi,

On Tue, Sep 24, 2019 at 11:41:54PM +0300, Avraham Shukron wrote:

> I have a library which I want to distribute in both shared object and
> static library forms.

Is that a requirement for your project, or a requirement for the system
integrator?

With my Debian Developer hat on, I'm always grateful when a project's build
system doesn't do anything unexpected.

We know that libtool generates shared and static libraries at the same
time, and so when wrapping an autoconf based project, we use a single build
tree and expect both to pop up.

With CMake, we know that the build system cannot generate both at the same
time. It would be cool if it could, but the expectation is that a library
project will have to be built twice, and our tools mirror that expectation.

If the majority of your users compile from source and need both shared and
static libraries to be built, it makes sense to have two targets.
Otherwise, the principle of least surprise applies.

That said, a hypothetical future version of CMake that makes this easier so
we can at some point remove the requirement to build twice would be
awesome.

   Simon
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Single library with both shared and static binaries

Juan Sanchez
In reply to this post by CMake mailing list
Here is an example where two libraries are created from object files that have only been compiled once:

ADD_LIBRARY(symdiff_objects OBJECT ${CXX_SRCS} ${MC_SRCS})
set_property(TARGET symdiff_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
ADD_LIBRARY(symdiff_dynamic STATIC $<TARGET_OBJECTS:symdiff_objects>)
ADD_LIBRARY(symdiff SHARED $<TARGET_OBJECTS:symdiff_objects>)

The "symdiff_dynamic" library is a static archive that can then be linked into another shared library or an executable. The "symdiff" library is a standalone object.  The POSITION_INDEPENDENT_CODE property is required for the linux platform, but not for macOS or Windows.  If the original poster is comfortable with having a PIC static library, this is an approach they can take.

Regards,

Juan

On Wed, Sep 25, 2019 at 8:43 AM Kyle Edwards via CMake <[hidden email]> wrote:
On Tue, 2019-09-24 at 23:41 +0300, Avraham Shukron wrote:
> Hi!
>
> I have a library which I want to distribute in both shared object and
> static library forms.
> Is there a modern way to do it without creating two completely
> separate library targets?
> Since I want to be a good CMake citizen I use `target_*` and
> `set_target_properties` as much as possible, and creating two
> different libraries will force me to duplicate that information about
> each one of them.
>
> I also tries not specifying STATIC/SHARED, and then running cmake
> twice - once with BUILD_SHARED_LIBS=ON and once OFF and then
> installing to the same directory. I got my both .a and .so libraries
> installed, but I couldn't get the Config file correctly for this
> arrangement.
>
> So - what is the community-recommended pattern to do this?

Unfortunately, the recommendation is to do exactly what you don't want
to do: create a shared target and a static target.

To make this slightly simpler, you can use functions to de-duplicate
the target_* and set_target_properties calls:

function(create_foo_target name type)
  add_library(${name} ${type} foo.c foo.h)
  set_target_properties(${name} OUTPUT_NAME foo)
endfunction()

create_foo_target(foo_shared SHARED)
create_foo_target(foo_static STATIC)

Kyle
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake

--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Single library with both shared and static binaries

Avraham Shukron
There is no hard requirement for shipping both static and shared. With the back against the wall I could get away with SHARED only, since it is the most common way the library will be consumed. I wanted to also distribute a static version just for those who want a single, self-contained executable.

I understand that static and shared libraries ARE in fact two different target, but for the most part they are configured the same way and have the same properties.

The fact that the recommended practice is to NOT specify SHARED / STATIC in add_library and let the user decide which one to compile using BUILD_SHARED_LIBS, proves that a library target is expected to be independent on whether it is compiled as a shared object or static library.

I agree that it would be great to have the ability to produce both shared and static binaries from a single library target, although we need to think of how users importing such target, will be able to specify if they want to link against the static or the shared binary.


On Thu, Sep 26, 2019 at 5:38 PM Juan Sanchez <[hidden email]> wrote:
Here is an example where two libraries are created from object files that have only been compiled once:

ADD_LIBRARY(symdiff_objects OBJECT ${CXX_SRCS} ${MC_SRCS})
set_property(TARGET symdiff_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
ADD_LIBRARY(symdiff_dynamic STATIC $<TARGET_OBJECTS:symdiff_objects>)
ADD_LIBRARY(symdiff SHARED $<TARGET_OBJECTS:symdiff_objects>)

The "symdiff_dynamic" library is a static archive that can then be linked into another shared library or an executable. The "symdiff" library is a standalone object.  The POSITION_INDEPENDENT_CODE property is required for the linux platform, but not for macOS or Windows.  If the original poster is comfortable with having a PIC static library, this is an approach they can take.

Regards,

Juan

On Wed, Sep 25, 2019 at 8:43 AM Kyle Edwards via CMake <[hidden email]> wrote:
On Tue, 2019-09-24 at 23:41 +0300, Avraham Shukron wrote:
> Hi!
>
> I have a library which I want to distribute in both shared object and
> static library forms.
> Is there a modern way to do it without creating two completely
> separate library targets?
> Since I want to be a good CMake citizen I use `target_*` and
> `set_target_properties` as much as possible, and creating two
> different libraries will force me to duplicate that information about
> each one of them.
>
> I also tries not specifying STATIC/SHARED, and then running cmake
> twice - once with BUILD_SHARED_LIBS=ON and once OFF and then
> installing to the same directory. I got my both .a and .so libraries
> installed, but I couldn't get the Config file correctly for this
> arrangement.
>
> So - what is the community-recommended pattern to do this?

Unfortunately, the recommendation is to do exactly what you don't want
to do: create a shared target and a static target.

To make this slightly simpler, you can use functions to de-duplicate
the target_* and set_target_properties calls:

function(create_foo_target name type)
  add_library(${name} ${type} foo.c foo.h)
  set_target_properties(${name} OUTPUT_NAME foo)
endfunction()

create_foo_target(foo_shared SHARED)
create_foo_target(foo_static STATIC)

Kyle
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake

--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Single library with both shared and static binaries

J Decker
I ended up using external_project() because unless you also copy the source files, each source file each only gets one set of flags... so if you have different compile options (the config file I suppose) the sources will only build with one or the other.

If you copy all of the sources to the CMAKE_BiNARY_DIR (which can be done passing a list of sources to a macro, which can then extract the path part and append it) then use copy_file_if_different()  (And I additionally touch that file to make sure the copy definitely gets built when it dos get copied)  then you can build two targets with different options for the sources.

Otherwise, an internal external project works pretty well.

I kinda moved away from building both dynamic static libaries,and the static binaries are just external projects that reference the original sources.    


On Thu, Sep 26, 2019 at 1:06 PM Avraham Shukron <[hidden email]> wrote:
There is no hard requirement for shipping both static and shared. With the back against the wall I could get away with SHARED only, since it is the most common way the library will be consumed. I wanted to also distribute a static version just for those who want a single, self-contained executable.

I understand that static and shared libraries ARE in fact two different target, but for the most part they are configured the same way and have the same properties.

The fact that the recommended practice is to NOT specify SHARED / STATIC in add_library and let the user decide which one to compile using BUILD_SHARED_LIBS, proves that a library target is expected to be independent on whether it is compiled as a shared object or static library.

I agree that it would be great to have the ability to produce both shared and static binaries from a single library target, although we need to think of how users importing such target, will be able to specify if they want to link against the static or the shared binary.


On Thu, Sep 26, 2019 at 5:38 PM Juan Sanchez <[hidden email]> wrote:
Here is an example where two libraries are created from object files that have only been compiled once:

ADD_LIBRARY(symdiff_objects OBJECT ${CXX_SRCS} ${MC_SRCS})
set_property(TARGET symdiff_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
ADD_LIBRARY(symdiff_dynamic STATIC $<TARGET_OBJECTS:symdiff_objects>)
ADD_LIBRARY(symdiff SHARED $<TARGET_OBJECTS:symdiff_objects>)

The "symdiff_dynamic" library is a static archive that can then be linked into another shared library or an executable. The "symdiff" library is a standalone object.  The POSITION_INDEPENDENT_CODE property is required for the linux platform, but not for macOS or Windows.  If the original poster is comfortable with having a PIC static library, this is an approach they can take.

Regards,

Juan

On Wed, Sep 25, 2019 at 8:43 AM Kyle Edwards via CMake <[hidden email]> wrote:
On Tue, 2019-09-24 at 23:41 +0300, Avraham Shukron wrote:
> Hi!
>
> I have a library which I want to distribute in both shared object and
> static library forms.
> Is there a modern way to do it without creating two completely
> separate library targets?
> Since I want to be a good CMake citizen I use `target_*` and
> `set_target_properties` as much as possible, and creating two
> different libraries will force me to duplicate that information about
> each one of them.
>
> I also tries not specifying STATIC/SHARED, and then running cmake
> twice - once with BUILD_SHARED_LIBS=ON and once OFF and then
> installing to the same directory. I got my both .a and .so libraries
> installed, but I couldn't get the Config file correctly for this
> arrangement.
>
> So - what is the community-recommended pattern to do this?

Unfortunately, the recommendation is to do exactly what you don't want
to do: create a shared target and a static target.

To make this slightly simpler, you can use functions to de-duplicate
the target_* and set_target_properties calls:

function(create_foo_target name type)
  add_library(${name} ${type} foo.c foo.h)
  set_target_properties(${name} OUTPUT_NAME foo)
endfunction()

create_foo_target(foo_shared SHARED)
create_foo_target(foo_static STATIC)

Kyle
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake

--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake