The Phabricator review for this RFC is here: D153426 Support LLVM_BUILD_USER_FORTRAN_LIBS=[shared|static|all] cmake option
For this post, assume that “user Fortran libraries” and “Flang runtime libraries” refer to the same thing, the libraries in question are libFortranRuntime
and libFortranDecimal
, which are the two libraries linked into user executables that we care to be able to control the link type of. Also note that libFortranDecimal
also gets linked into flang-new
when building the compiler, this is a primary reason for this patch.
The goal we are trying to achieve through this patch is to have more control over what link types we are building for the Flang runtime libraries, independently of the link types built and linked into the compiler at build time.
There is an important distinction between which library link types are built, and which types are linked into what. We want to separate control over these so that when we are building the compiler we can choose:
- whether we want LLVM libs to be (built and then) linked as shared or static into flang-new (All LLVM libs, including
FortranDecimal
) - whether to build the Flang runtime libraries (which includes
FortranDecimal
as well) as static or shared. Note that the usage (actual linking) of these libraries will only occur later by the user of the compiler.
Currently the link type that’s built is primary decided by whether BUILD_SHARED_LIBS
is set. CMake seems to default on building the libs as static unless BUILD_SHARED_LIBS
is set, in which case it prefers to build them as shared. However, if the call to the llvm_add_library
function explicitly specifies a lib type, that type takes precedence over BUILD_SHARED_LIBS
, because of this, some libs always get built with a certain link type.
The solution experimented with in the patch linked at the top of this post is using a new CMake variable (currently named LLVM_BUILD_USER_FORTRAN_LIBS=shared|static|all
but likely to change to something more correct like FLANG_BUILD_RUNTIME_LIBS
instead) that appends additional link types to the call to llvm_add_library
, therefore explicitly ensuring that whatever link type is passed by this variable will be built in addition to whatever was determined by BUILD_SHARED_LIBS
or any defaults.
Note that we don’t want this new variable to impact how flang-new gets linked. The following case can be troublesome:
Lets say we do not specify BUILD_SHARED_LIBS
, we want to statically build and link the LLVM libs into flang-new
, however we also specify FLANG_BUILD_RUNTIME_LIBS=shared
because we want to dynamically link user executables when using our driver. The problem is that CMake refers to libraries by their name, without the file extension (.a
vs .so
), so the static and shared libs need to have unique names so they do not cause errors in the CMake code. The code to handle this already exists in AddLLVM.cmake
. If the llvm_add_library
function is called for a lib named “Foo”, with explicit shared and static libtype arguments (this is what will happen for FortranDecimal
and FortranRuntime
if FLANG_BUILD_RUNTIME_LIBS=shared
is used like in this example) then 2 separate add_library
CMake function calls are made, one with the lib name “Foo” and lib type of shared, and one named “Foo_static” with a lib type of static.
This can be problematic because other CMake code is searching for these library targets by name, and if we want to preserve the preference for static linking (since BUILD_SHARED_LIBS
was not specified) we now need to make sure that all the usages of libraries that got double built know that they need to use the “_static” variant. Since this new variable only affects a short list of Flang-specific libraries, the patch currently just adds a global property that is set whenever both lib types get built (and therefore “_static” named libs exist) and then this global is checked for at all the usages of FortranRuntime, FortranDecimal (the patch currently also experiments with the idea of a BUILD_STATIC_LIBS
variable that is checked, the theory being that if you set BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS
thats another case where “_static” libs are created. In retrospect, I don’t think introducing this is necessary, will probably remove from this patch). We also need to ensure that this difference in name is handled somehow so that flang-new will properly link against the “_static” libs if we are explicitly statically linking (ie flang-new --static
).
The patch is work-in-progress and I am looking to start discussion about all the information above.
Below is a table covering the behavior I think we want for all the different combinations of the configurations covered in this post. Please let me know if something in this table seems misaligned with other expectations:
BUILD_SHARED_LIBS | FLANG_BUILD_RUNTIME_LIBS | flang-new --static | Expected behavior |
---|---|---|---|
TRUE | all | TRUE | All the libs get built as shared. In addition, the Flang runtime libs also get built as static. flang-new will be linked against all the shared libs. The flang-new driver will look for and find the static runtime libs to use at runtime. |
TRUE | all | FALSE | Same as above except that since --static is not passed to flang-new , the driver will look for and use the shared libs by default. |
TRUE | static | TRUE | Same as the entry 2 rows up. FLANG_BUILD_RUNTIME_LIBS appends the static link type to the list of link types to be built. |
TRUE | static | FALSE | Same as entry 2 rows up. |
TRUE | shared | TRUE | All the libs get built as shared. FLANG_BUILD_RUNTIME_LIBS does not do anything in addition. The libs are linked into flang-new as shared. When using flang-new --static , the driver throws an error as it is unable to find static versions of the runtime libs. |
TRUE | shared | FALSE | Same as previous entry except that the flang-new driver does not throw an error since its looking for and will find the shared libs. |
FALSE | all | TRUE | Libs are preferred to build and be linked into the compiler statically by default by CMake if BUILD_SHARED_LIBS is not set. The Flang runtime libs get built additionally as shared. The driver is able to find and use the static libs at runtime. |
FALSE | all | FALSE | Same as above except the driver finds and uses the shared libs by default. |
FALSE | static | TRUE | All the libs get built statically and linked statically into both the compiler and user executables. |
FALSE | static | FALSE | All the libs get built statically and linked statically into the compiler and implicitly into user executables. |
FALSE | shared | TRUE | All the libs get built statically and linked statically into the compiler. In addition, the Flang runtime libs get built as shared. The flang-new driver links the static libs into user executables. |
FALSE | shared | FALSE | Same as previous entry except the driver finds and uses the shared libs by default. |