Closed bartlettroscoe closed 1 year ago
This refactoring will make it easier to integrate Kokkos and KokkosKernels into Trilinos as described in the below email from @jjwilke.
From: Wilke, Jeremiah J jjwilke@sandia.gov Sent: Tuesday, February 4, 2020 4:18 PM To: Wolf, Michael M mmwolf@sandia.gov; Rajamanickam, Sivasankaran srajama@sandia.gov; Bartlett, Roscoe A rabartl@sandia.gov; Willenbring, James M jmwille@sandia.gov; Trott, Christian Robert crtrott@sandia.gov; Teranishi, Keita knteran@sandia.gov Subject: To-do list for Trilinos
Below would be my (very specific) action items to get where we need to be.
• Move to CMake 3.13 (allows link_options and better with flag deduplication) • Change variables to lists instead of strings (where appropriate) • Change include_directories/compile_options to target_include_directories(….) • Remove all dependencies between packages that rely on variables. Only use target_link_libraries(…) to propagate flags
I would guess this could be done in a month? Once this is done, it should be straightforward to design a system where Kokkos could be a TPL.
-Jeremy
The Trilinos issue to allow the upgrade of the minimum version of CMake from 3.10 to 3.13 for TriBITS as well is trilinos/Trilinos#6752.
@jjwilke, @sethrj,
This brings up another issue. These refactorings of TriBITS to use target-centric features in CMake may make it very difficult to maintain backward comparability with-respect to the build system. For example, it may not be possible keep supporting the generation of Makefile.export.<Package>
files for customers like INL MOOSE. Trilinos backward-comparability requirements might make that difficult to allow.
I think we can probably make this work? Everything that needs to be in the Makefile will end up in INTERFACE_COMPILE_OPTIONS
, INTERFACE_LINK_LIBRARIES
, etc. We could probably make a function
FUNCTION(EXPORT_TARGET target)
...
That doesn't rely on variables like Kokkos_CXX_FLAGS
and instead calls get_property
to figure everything out.
This will also be relevant to https://github.com/TriBITSPub/TriBITS/issues/127#issuecomment-549912354.
FWIW, SCALE/Exnihilo is only using the exported tribits config.cmake files for the downstream enrico project, not any makefile.export.
I'm definitely OK with a transition plan for removing backward compatibility gradually 😬
I will say (and maybe @bradking already knows how to do this) - the reason I stopped short of exporting a Makefile.kokkos was generator expressions in the property lists.
stopped short of exporting a Makefile.kokkos was generator expressions in the property lists.
Modern CMake target-based usage requirements mean that much of the logic to convert project CMake code into the final build system command-lines is handled by CMake's generators. The input to that process is not exportable to Makefile.*
, and the output is only available in generated build systems inside CMake-generated build trees. Easy export to Makefile snippets was not a design goal.
Easy export to Makefile snippets was not a design goal.
It occurred to me that it still might be possible to produce Makefile.*
files. What you do is you create a dummy CMake project that pulls in TrilinosConfig.cmake
or <Package>Config.cmake
and then you use your own compiler and linker wrappers to capture the compiler and linker arguments and use that to generate the Makefile.export.*
files. That is almost exactly what the ASC Sierra project does with their "bake" tool to generate Makefiles and build.ninja files given output from a Bjam build system. Crude but that would work.
FYI: I just got feedback from lead INL MOOSE framework lead that they dropped testing against Trilinos (because CASL has ended) and don't plan on supporting Trilinos going forward (unless something changes). Therefore, because I think we could add support for Makefile.export.*
files like a described above, and it is not needed now, I will remove testing and support for this in TriBITS when I do this refactoring. Yea!
FYI: It just occurred to me that the SNL Sierra project might be using Makefile.export.Trilinos for its custom bJam/bake build system that uses the native Trilinos TriBITS/CMake build system. I have reached out to them to see if that is the case.
FYI: Got back a response from the SNL Sierra DevOps lead that Sierra actually does not use the Makefile.export.Trilinos file. They actually manually maintain a set of BJam files for building Trilinos and they get the info they need from that (even when building Trilinos using the native TriBITS CMake build system).
Therefore, it looks like we don't need to keep generating Makefile.export.Trilinos files based on SNL Sierra needs. That is good news :-)
Part of this refactoring is in the PR #300 from @bradking. It removes explicit handing of -std
compiler options. It sets the global var CMAKE_CXX_STANDARD
and it sets:
TARGET_COMPILE_FEATURES(<libtarget> PUBLIC <cxx_std>)
to that matching standard.
Someone just showed me the option CMAKE_EXPORT_COMPILE_COMMANDS which writes a comple_commands.json
file after the generate phase is complete. From that you can easily extract the information needed for Makefile.export.*
files (but that would have to be created by a build target, after configure and generate were complete). Now to get other things out of the way so I can get into this.
FYI: I just realized that PETSc is still using the Makefile.export.Trilinos
file to get the list and order of Trilinos libraries. See:
So I think unless PETSc switches over to CMake, we are going to need to re-implement support for at least the Makefile.export.<Project>
file as part of this refactoring :-(
Or just require PETSc to use older trilinos/tribits version until they switch?
Or just require PETSc to use older trilinos/tribits version until they switch?
Not sure that is a viable option because of the ECP xSDK and E4S that includes PETSc and Trilinos. But to get by, someone can just manually generate a Makefile.export.Trilinos
file in the Spack Trilinos package.py
file and that would satisfy PETSc for now for Spack and ECP.
And I have no idea what the timetable would be for PETSc to switch to CMake (or even if that is a firm plan).
CC: @keitat
FYI: Looks like the refactored TriBITS may need to need to keep defining the vars TPL_<TPLName>_INCLUDE_DIRS
due to code like:
I wonder how much code like this exists in Trilinos and other projects using Trilinos?
This issue came up at SART meeting today. At least Xyce is still using export makefiles. They are in the process of transitioning to cmake, but it may be a few months. Will need to coordinate with them. Have sent inquiries to other code teams to see how wide spread the export makefile use is. Will add more info soon.
@bartgol This would affect Albany and the export of the libraries for MPAS, right?
FYI: Xyce should be getting some help from Kitware to transition fully to CMake so hopefully the export Makefile requirement for TriBITS and Trilinos can go away completely.
FYI: trilinos/Trilinos#8498
I guess I am technically starting on this Issue today. I am upgrading TriBITS to require CMake 3.17+ given that Trilinos has already upgraded is min version to 3.17 (see trilinos/Trilinos#8660). This will involve cleaning up a good bit of code and getting rid of various workarounds and hacks for older versions of CMake.
Related to my epic SEPW-214
@keitat, do you think that you can have some of the subcontractor staff looking into Trilinos xSDK issues help review PRs related to this and TriBITS changes in general? I desperately need someone to help review TriBIITS changes that really knows CMake well.
Stay tuned. I will let you know the github username of the people from NGA.
FYI: It looks like there is an important internal customer that would be significantly impacted if Trilinos looses support for Makefile.export.Trilinos in the next few months (or longer). This refactoirng can't wait any longer so if support for Makefile.export.Trilinos has to be maintained, then we might just have to bit the bullet and implement an approach like they did for ParaView/VTK shown in:
which is outlined in https://github.com/trilinos/Trilinos/issues/8498#issuecomment-825349056 which is basically what I suggested above last year. The fact that Kitware has already implemented this approach for a major project gives me some comfort that this may not be as big of a hack as what I was thinking this was.
But note that this file Makefile.export.Trilinos would get generated at build time, not configure time, and use cases like the integration of INL MOOSE into VERA and demonstrated with the WrapExternal package would not longer work (or would have to work very differently with the configure of the wrapped external project done at build time, not configure time of the outer TriBITS CMake project).
Just goes to show that once an important piece of software acquires a feature that is important to some customer, that you can never remove support for that feature :-(
The fact that Kitware has already implemented this approach for a major project gives me some comfort that this may not be as big of a hack as what I was thinking this was.
I wouldn't call it a "big hack", but it is a hack in the sense that it doesn't solve the problem. For example, VTK's object factory stuff is absent there, so that is still manual. There are probably other usage requirements that are missing. If a project has Fortran-specific usage requirements, the synthesized project has to use Fortran for those to be exposed.
Basically, the example project needs to encompass the use cases that exist then have ways of teasing out what is wanted. That's where the "hackiness" comes in: you're making tiny examples then trying to extrapolate it for full usage which doesn't always work. I would stick huge disclaimers on this that CMake is the preferred way to use Trilinos and that this exporting mechanism is a best-effort attempt at bridging the gap.
FYI: That internal SNL customer still using Makefile.export.*
files for a daily integration with Trilinos 'master' is going to try switching that build over to using their new CMake build system for their application code. They will try to get that done in the next few weeks. Then they will plan to officially switch to CMake for all of their builds before their next major upgrade of Trilinos based on the current Trilinos 'master' branch.
Therefore, I need to wait until they give me the green light before I merge a version of TriBITS to Trilinos 'develop' that drops support for Makefile.export.*
files.
FYI: After talking with that internal customer still using Makefile.export.*
we may be able to switch them over to use CMake for their daily integration builds against Trilinos 'master' and avoid needing to support Makefile.export.*
, even in the short-term. For details, see https://github.com/trilinos/Trilinos/issues/8498#issuecomment-834681399. Fingers crossed that transition to CMake for the customer will be completed soon so we are not blocked from dumping support for Makefile.export.*
and get this TriBITS refactoring to use modern CMake done. But we can't push an updated version of TriBITS that drops support for Makefile.export.*
to Trilinos 'mastesr' until that customer's daily APP 'master' + Trilinos 'develop' integration build is switched over to use CMake. I just don't want to be doing this work on another long-lived branch of TriBITS like I did with the branch 63-merge-tpls-packages that still is not merged in (but will be soon since it should not break backward compatibility).
Good news. As stated in https://github.com/trilinos/Trilinos/issues/8498#issuecomment-850503201, it looks like we can finally drop support for Makefile.export.*
files from Trilinos (and therefore TriBITS)! I promised to keep support in the Trilinos 'develop' through 5/10/2021 but that is just a little under 2 weeks from now.
I realized that I can do a lot of the refactoring to create the new targets supporting modern CMake incrementally and safety without breaking backward compatibility initially to see how this works before actually needing to drop support for Makefile.export.*
. For example, I can create targets <PackageName>::all_libs
for all of the TPLs and packages and ensure these targets actually work to link executables in a dummy TriBITS-lite example/test project.
So given where I am with the recent refactorings/cleanups in #63 as part of epic #367, I am ready to start extending TriBITS to provide fully modern CMake targets as per this proposed standard next week!
@marcinwrobel1986, see commit 3ac791bcf0cec15bf8753287c9ba475262e88fa5. We need to test with Trilinos and a (dummy) customer APP. Perhaps we can meet offline briefly for details if you have time and funding for this?
Below I summarize an email chain and then a meeting I had Ben Boeckel of Kitware about how to deal with a difficult issue related to moving to self-contained modern CMake targets which includes for external packages / TPLs where the TPLs may be specified as just a list of link flags and there may be upstream dependencies. There is a workable implementation path that I will summarize below. The motivating email chain is below that.
The problem is that target_link_libraries()
allows the user to pass in link options like:
target_link_libraries(<libName> -L<dir> -l<lib> ...)
and TriBITS allowed users to specify TPL libraries in that way as described here which warned not to do:
TPL_SomeTPL_LIBRARIES="-L/some/dir;-llib1;-llib2;..."
But a lot of people's Trilinos configure scripts did just this.
But to create self-contained library targets for these external packages/TPLs that know their upstream dependencies as well, we need to create <tplName>Config.cmake
files that contain imported targets. The way to do this is to take advantage of the target property IMPORTED_LIBNAME
, which when combined with INTERFACE_LINK_OPTIONS
, allows you to take a list of link arguments like:
-L<dir> -l<lib>
and define and IMPORTED INTERFACE
library that allows passing these options to the link line with -l<lib>
in the right location.
I experimented with this in the PR #412 commit https://github.com/TriBITSPub/TriBITS/pull/412/commits/e11ac0e17ebd599fd940016aca54f6454157a2e2 and it seemed to work as it should.
By parsing the list of options one should be able to separate out the -L<dir>
and -l<lib>
parts in a set of options like:
-L<dir1> -l<lib1> -L<dir2> -l<lib2> …
and create a set of IMPORTED INTERFACE
libraries, one target <tplName>::<libi>
library for each -l<libi>
option, and then create an INTERFACE
library target <tplName>::all_libs
that links against these and sets the -L<diri>
arguments with target_link_options()
to build the full link line. You can see where I successfully experimented with that in the PR #412 commit https://github.com/TriBITSPub/TriBITS/pull/412/commits/c5962b87e9acbc752576e5c53399094362547b83.
However, this is not a 100% bulletproof solution because it is possible that other link options can exist like -Wl,-Bstatic or -Wl,Bdymanic
that would not be able to be handled with IMPORTED_LIBNAME
but I think these are pretty rare and we could warn or error out if we encounter link options other than start with anything other than -L
or -l
(or are a full lib path).
Looking at the ATDM Trilinos configuration files under:
Trilinos/cmake/std/atdm/
using:
$ cd Trilinos/cmake/std/adm/
$ find . -type f -exec grep -nH "[ ;\"][-]l" {} \; | grep -v "~:" | fold -w 180 | less
I can’t find a single example where a TPL is specified with anything other than -L<dir>, -l<lib>
or a complete library path.
Therefore, with this, I believe we have a solution that can handle 99% or more of the configuration scripts out there for Trilinos (and 100% of the ATDM Trilinos configurations) and allow the creation of fairly straightforward <tplName>Config.cmake
files for TriBITS TPLs with IMPORTED
and INTERFACE
targets for external packages/TPLs where there are dependencies on each other and there are some TPLs that are specified as a set of -L<dir>
and -l<lib>
options.
Below, is the email chain in this conversation.
FYI: TriBITS PR #424 converts internal TriBITS targets to use modern CMake and the updated internal targets and generated <Package>Config.cmake
files mostly satisfies the proposed convention in #342. As noted in PR #424, I still need to address the handling of external packages/TPLs before I can rip out all of the old complex TriBITS logic and complete this issue #299 but I have a pretty good plan for that and my recent experiences gives me hope that will go okay.
Now if I could just find someone to review the documentation and examples in PR #424 and get some early feedback.
FYI: Related to #340, as described in #427, there are issues with TriBITS-generated <tplName>Config.cmake
files when FindTPL<tplName>Config.cmake
modules call find_package(<tplName>)
. One issue raised in #427 is that find_package()
will look under CMAKE_INSTALL_PREFIX
. That is a tricky issue that I will need to address somehow.
CC: @mperrinel, @marcinwrobel1986, @keitat
While debugging the errors with the updated TriBITS with Trilinos with Albany I came across a bit of an issue. The problem is that it seems that application codes like Albany have not been always following the suggested usage of pulling in libraries using the variables <PackageName>_LIBRARIES
but instead have been, in some cases, directly linking to the non-namespaced IMPORTED targets for libraries that are defined by the found <Package>Config.cmake
files (included by the TrilinosConfig.cmake
file through find_package(Trilinos)
). For example, Albany/src/CMakeLists.txts had code like:
showing:
add_executable(xml2yaml utility/xml2yaml.cpp)
...
target_link_libraries(xml2yaml teuchosparameterlist)
...
target_include_directories(xml2yaml SYSTEM PUBLIC
"${Trilinos_INCLUDE_DIRS};${Trilinos_TPL_INCLUDE_DIRS}")
When the old TriBITS implementation, teuchosparameterlist
is an actual IMPORTED target and CMake uses this to create a successful link line for the xml2yaml
executable in the Albany build system.
But with the new TriBITS, there is no non-namespaced IMPORTED target called teuchosparameterlist
(it is the namespaced target TeuchosParameterList::teuchosparameterlist
). Therefore, when CMake processes the line
target_link_libraries(xml2yaml teuchosparameterlist)
with the updated <Package>Config.cmake
files for the updated TriBITS, there is no existing target of that name. And in this case, CMake assumes that teuchosparameterlist
is just some dumb library out on the system and it puts a -lteuchosparameterlist
on the link line as demonstrated in the detailed debugging in Detailed debugging notes in:
This is a very "helpful" feature of CMake's target_link_libraries()
command as documented under the section A plain library name at:
The fix for this is simple. Applications should just have used the proper TriBITG-defined variables ${<Package>_LIBRARIES}
and linked against that instead as shown in the PR:
in lines:
showing:
add_executable(xml2yaml utility/xml2yaml.cpp)
...
target_link_libraries(xml2yaml PUBLIC ${TeuchosParameterList_LIBRARIES})
...
target_include_directories(yaml2xml SYSTEM PUBLIC
"${TeuchosParameterList_INCLUDE_DIRS};${TeuchosParameterList_TPL_INCLUDE_DIRS}")
And that works with both the old and the new TriBITS.
The variables:
<Package>_LIBRARIES
<Package>_INCLUDE_DIRS
<Package>_TPL_INCLUDE_DIRS
are the TriBITS interface that I have been targeting maintaining (and the PR https://github.com/sandialabs/Albany/pull/778 and the testing associated with that demonstrates that still works).
I think the problem here is that the APP teams did not know how to find Trilinos using find_package(Trilinos)
and then just link against a subset of the packages that are found. Therefore, they just guessed, and in the case of Albany, grabbed the raw targets instead of linking against the proper varaibles.
The issue is that when Trilinos support for TrilinosConfig.cmake
and the <Package>Config.cmake
files was first created (by developers other than me), on one documented how they were supposed to be used or how customer APPs/packages were supposed to link against just a subset of package libraries. I did not get involved in writing this documentation until just last year and by that point the ship had sailed for all of these APPs.
So that this point, we have one of two options to move forward from here:
Option-1: Try to add back the old non-namespaced IMPORTED library targets like teuchosparameterlist
in addition to the new namespaced targets TeuchosParamterList::teuchosparameterlist
(and of course the TeuchosParamterList::all_libs
target which customers are supposed to be linking against).
Option-2: Send out emails informing the application teams of incorrect usage of TriBITS and ask them to check their CMakeLists.txt files for direct linking against raw imported targets and fix them to be ${<Package>_LIBRARIES}
.
If we go with option-1, then that should provide better (hopefully about perfect) backward compatibility. But then how do we later remove these non-namespaced targets and help the application codes to move to the new proper namespaced targets?
If we go with option-2, then the APPs will experience nasty build errors like was seen for Albany as demonstrated in:
and it is not clear what is happening.
Note that once the updated TriBITS is merged to Trilinos, then APPs can just link against <PackageName>::all_libs
and can stop using the include dirs altogether. That would make this Albany/src/CMakeLists.txt code just be:
add_executable(xml2yaml utility/xml2yaml.cpp)
...
target_link_libraries(xml2yaml PUBLIC TeuchosParameterList::all_libs)
To decide between option-1 and option-2, I need to get advice from some experienced CMake people to get their opinions on how to proceed. I will ask the NextGen people and my Kitware contractors as well.
In the meantime, I will see if this issue might be impacting Nalu as well (which is another APP with a public Git repo).
Okay, I just found that there is DEPRECATION
target property for CMake 3.17+:
With that, we could go with option-1 above and deprecate these old non-namespaced CMake targets so that, at configure time, if someone tried to link against a deprecated IMPORTED target, then it would generate a warning.
Given this discovery, I think that is the way to go with option-1 and set the DEPRECATION
target property. These <libname>
targets would be ALIAS targets against the proper namespaced targets <Package>::<libname>
. The question is, how do we generate those targets in the <Package>Config.cmake
files?
But then how do we later remove these non-namespaced targets and help the application codes to move to the new proper namespaced targets?
Make it depend on the requested version of Trilinos (or the package in question). If that is at least the version which provides the new targets, do not create the backwards compat bits. If it is explicitly lower, consider dropping the DEPRECATION
property (because that target needs to be used to work across the requested version range). After "enough time" (i.e., when "everyone" could have been expected to migrate), this deprecation can become unconditional. If it is left empty, always add the DEPRECATION
property.
Given this discovery, I think that is the way to go with option-1 and set the DEPRECATION target property. These
targets would be ALIAS targets against the proper namespaced targets :: .
This sounds reasonable.
The question is, how do we generate those targets in the
Config.cmake files?
There's the list of libraries that goes into all_libs
already? Can't that be reused?
I agree with option-1 for the reasons posted above. However, option-1 and option-2 are not mutually exclusive. Even if Trilinos were not changing to the namespaced targets, the application teams should still replace their direct non-namespaced target usage with ${<Package>_LIBRARIES}
to avoid using undocumented names. The variable references will then work with old versions of Trilinos too. A deprecation warning from option-1 will help teams implement option-2 if they don't want to raise their minimum required version of Trilinos.
@mathstuf,
There's the list of libraries that goes into
all_libs
already? Can't that be reused?
Yes, I know how to get that list but I was hopping that I could just get CMake to generate these targets automatically with the export() command. But given how the targets are defined and used currently using the namespacing, I am not sure If CMake will let me do this. I will experiment with this and see what CMake will allow me to do. If nothing else, I think I know how to create these ALIAS DEPRECATION non-namespaced targets directly in the generated <Package>Config.cmake
file. (But again, I would rather if CMake would just do this for me with the right arguments to the right commands.)
@bradking,
Even if Trilinos were not changing to the namespaced targets, the application teams should still replace their direct non-namespaced target usage with
${<Package>_LIBRARIES}
to avoid using undocumented names. The variable references will then work with old versions of Trilinos too.
Right, but the question is if we should expect non-compliant customers to refactor their CMakeLists.txt files twice. Once to refactor from the current non-namespaced targets:
target_link_libraries(xml2yaml teuchosparameterlist)
to the variables ${<Package>_LIBRARIES}
:
target_link_libraries(xml2yaml PUBLIC ${TeuchosParameterList_LIBRARIES})
and then a second time to remove usage of variables and go with modern namespaced CMake targets <Package>::all_libs
by changing to:
target_link_libraries(xml2yaml PUBLIC TeuchosParameterList::all_libs)
(or Trilinos::TeuchosParamterList_libs
as per DRAFT: Proposed Standard for PackageConfig.cmake files for inter-package Interoperability).
@bradking and @mathstuf,
Now I understand this move of modern CMake to namespaced target names. From "Professional CMake: 10th edition"
Another important aspect of names having a double-colon (::) is that CMake will always treat them as the name of an alias or imported target. Any attempt to use such a name for a different target type will result in an error. Perhaps more usefully though, when the target name is used as part of a target_link_library() call, if CMake doesn’t know of a target by that name, it will issue an error at generation time. Compare this to an ordinary name which CMake will treat as a library assumed to be provided by the system if it doesn’t know of a target by that name. This can lead to the error only becoming apparent much later at build time.
That is what we are suffering from here. Old CMake used non-namespaced targets and if a target <some-lib>
become undefined, target_link_libraries( ... <some-lib>)
will just assume that <some-lib>
is out on the system and put in a -l<some-lib>
on the link line. That makes it impossible to catch errors in target names at configure or generation time. You only find out about errors at link time where it is very difficult to debug what is happening (unless you know to watch for this).
Given this information, I think that you should never link against a non-namespaced target in a call to target_link_libraries()
. CMake just provides not checking whatsoever at configure or generation time with raw non-namespaced names. Someone should have a list of basic CMake dos and don'ts and this needs to be on that list (both as "do create and link against namespaced targets" and "don't link against non-namespaced targets").
you should never link against a non-namespaced target in a call to
target_link_libraries()
FYI, CMake 3.23 adds an optional LINK_LIBRARIES_ONLY_TARGETS check to verify that plain names passed to target_link_libraries
are actually targets.
create these ALIAS DEPRECATION non-namespaced targets directly in the generated
Config.cmake file.
FYI, CMake 3.18 is required to create an ALIAS target that references a non-global imported target. ALIAS targets were not originally meant for this use case.
An alternative is to create a non-namespaced IMPORTED
INTERFACE
library that just sets INTERFACE_LINK_LIBRARIES
to the namespaced target's name.
hoping that I could just get CMake to generate these targets automatically...I am not sure If CMake will let me do this.
I don't think it will. While one might be able to call install(EXPORT)
twice, once with a namespace and once without, doing so would create two independent definitions of each target that don't de-duplicate and could double-up linking.
I think generating the compatibility targets yourself in TribitsProjectConfigTemplate.cmake.in
or similar may work best.
FYI, CMake 3.23 adds an optional LINK_LIBRARIES_ONLY_TARGETS check to verify that plain names passed to target_link_libraries are actually targets.
That is great news! Unfortunately, we can't turn this on for Trilinos right now due to people taking advantage of raw library names (see https://github.com/trilinos/Trilinos/pull/9978#issuecomment-982166363).
@bradking, would you recommend people change from passing raw <libname>
to target_link_libraries()
such as for:
-D TPL_BLAS_LIBRARIES:PATH="${OPENBLAS_PATH}/lib/libopenblas.a;gfortran;gomp;m"
to passing -l<libname>
:
-D TPL_BLAS_LIBRARIES:PATH="${OPENBLAS_PATH}/lib/libopenblas.a;-lgfortran;-lgomp;-lm"
?
Is -l<libname>
portable on Windows?
(I did not even realize that target_link_libraries()
accepted raw lib names like this until https://github.com/trilinos/Trilinos/pull/9978#issuecomment-982166363 was posted. I had never used that in 13+ years of my CMake usage. And yes, I know people should be using find_packge()
modules but that is a hard sell when people already have working configure scripts and people have really struggled with some of the Find<Package>.cmake
modules over the years.)
One of the issues we are struggling with here is that early versions of CMake were incredibly permissive so attempts we make to improve things and move to modern CMake often result in errors that are not caught until compile or link time where they are very hard for some people to debug. But I guess everyone is in the same boat. (But Trilinos has a lot of customers that configure, build, and then link against Trilinos on all types of crazy systems by thousands of non-CMake users across the planet.)
I think generating the compatibility targets yourself in
TribitsProjectConfigTemplate.cmake.in
or similar may work best.
@bradking. I can do that, but that means that I will need to add some machinery to keep a list of targets for which to create these INTERFACE IMPORTED
targets when generating the <Package>Config.cmake
file from TribitsPackageConfigTemplate.cmake.in. But I am already gathering that list of targets to form the
I just need to pass that list packageLibsInAllLibsList
to the generated file <Package>Config.cmake
and let it loop over to form the non-namespaced INTERFACE IMORTED
targets.
(NOTE: All of this code will get cleaned up significantly once we are done with this transition to full modern CMake inside of TriBITS. Getting rid of all of the variables and global properties will be one of the major goals.)
Raw library names are actually the preferred way to refer to toolchain-provided libraries, rather than find_library
, so that the toolchain can handle selecting the proper library file from its builtin paths. LINK_LIBRARIES_ONLY_TARGETS
documents a way to handle such libraries via IMPORTED_LIBNAME
on an interface library, but only when the project code knows the names itself.
Is
-l<libname>
portable on Windows?
No. That would just pass through directly to the link line as a flag, and the MSVC linker does not understand such syntax.
Who is responsible for passing ${TPL_BLAS_LIBRARIES}
to a target_link_libraries
call? Is project code free to do that, or does TriBITS handle it somewhere? In the latter case, it might be able to transform the content.
Who is responsible for passing
${TPL_BLAS_LIBRARIES}
to atarget_link_libraries
call? Is project code free to do that, or does TriBITS handle it somewhere? In the latter case, it might be able to transform the content.
@bradking, that is a good point. The TriBITS refactoring that I just finished actually does process the list in ${TPL_BLAS_LIBRARIES}
(all all the other TPLs) to create IMPORTED
library targets and does not rely on passing raw library names to target_link_libraries()
. So with the upgraded TriBITS, in theory, Trilinos could set LINK_LIBRARIES_ONLY_TARGETS=TRUE
. I created the backlog item https://github.com/trilinos/Trilinos/issues/10081 for this.
I am not reading the whole conversation, but I read that some changes won't happen due to downstream apps relying on "old" cmake patterns. FWIW, I wanted to make it clear that on the Albany side we are ok if Trilinos moves to moder cmake and breaks our builds. We will fix them up. Having more robust (and self-explanatory) cmake logic is definitely healthy, and I'm willing to take a few hours to adapt to whatever change you guys might do.
I know we're not the only/main trilinos customer, but I figured stating it clearly could help (especially if other apps are on the same page).
Consensus at meeting today involving @bradking, @mathstuf, @mperrinel, @keitat: go with option-1 and add back non-namespaced targets and add a good DEPRECATION
message that mentions the usage of ${<Package>_LIBRARIES}
to build against old and new TriBITS/Trilinos or just use the updated TriBITS/Trilinos and use<Package>::all_libs
and drop usage of the <Package>_INCLUDE_DIRS
and <Package>_TPL_INCLUDE_DIRS
variables.
FWIW, I wanted to make it clear that on the Albany side we are ok if Trilinos moves to modern cmake and breaks our builds. We will fix them up. Having more robust (and self-explanatory) cmake logic is definitely healthy, and I'm willing to take a few hours to adapt to whatever change you guys might do.
@bartgol, it is good that some customers are willing to absorb non-backward compatible changes. Long term, this has to happen if we are going to move to more robust modern CMake as a community. This issue is how painful does this need to be for everyone involved? For the case of linking against the old non-namespaced targets, that resulted in a link-time error what was not trivial to debug (at least not for me). We want to provide a smoother path to get customers to upgrade their usage of Trilinos for modern CMake and encourage them to adopt modern CMake. If it was a clear configure-time error, then I think that is likely okay. But a obscure link time error is not okay (at least not in my opinion).
Parent Issue:
367
Child Issues:
433
443
Blocked By: trilinos/Trilinos#8498
Description
One of the things holding back TriBITS and projects using TriBITS in accessing new features of CMake for which TriBITS still using variables to manage compiler options and include directories. This issue is to move to using:
and to move completely to targets instead of variables for each TriBITS (internal and external) package.
This needs to be done as part of a comprehensive refactoring as part of #63.
This refactoring should implement and respect this proposed standard for
<Package>Config.cmake
files.Related to:
Tasks
PUBLIC
totarget_link_libraries()
in TriBITS intra-package linking${PACKAGE_NAME}::<lib-name>
targets and${PACKAGE_NAME}::all_libs
INTERFACE library targets for TriBITS packages andtarget_link_libraries( ... PUBLIC ... )
to define dependencies to upstream packages. (see PR #424)${TPL_NAME}::all_libs
INTERFACE GLOBAL library targets for TPLs and usetarget_link_libraries( ... INTERFACE ... )
to define dependencies between TPLs.target_include_directories()
<Package>_INCLUDE_DIRS
,<Package>_TPL_INCLUDE_DIRS
,<Package>_LIBRARIES
or<Package>_LIBRARY_DIRS
).<Package>_INCLUDE_DIRS
,<Package>_TPL_INCLUDE_DIRS
,<Package>_LIBRARIES
and<Package>_LIBRARY_DIRS
.