[CMake] Contribute two new find package implementation.

Michael Hertling mhertling at online.de
Sun Oct 9 22:43:41 EDT 2011


On 10/09/2011 06:54 PM, Eric Noulard wrote:
> Argh... forgot the list
> 
> 
> ---------- Forwarded message ----------
> From: Eric Noulard <eric.noulard at gmail.com>
> Date: 2011/10/9
> Subject: Re: [CMake] Contribute two new find package implementation.
> To: Michael Hertling <mhertling at online.de>
> 
> 
> 2011/10/9 Michael Hertling <mhertling at online.de>:
>> On 10/07/2011 07:06 PM, Eric Noulard wrote:
>>> 2011/10/7 Mathias Fröhlich <M.Froehlich at science-computing.de>:
>>>> On Friday 07 October 2011, Eric Noulard wrote:
>>
>>>>> Concerning 1516 and 1516e specific module may be it would be interesting
>>>>> to only have one module "FindRTI.cmake" .
>>>> Sure this is there and finds the rti13 libs.
>>>>
>>>>> I think we cannot really use the VERSION argument of find_package
>>>>> but may be
>>>>>
>>>>> find_package(RTI COMPONENTS HLA13 IEEE1516)
>>>>> would be nice?
>>>> Hmm, I have done seperate versions because I was willing to find all three
>>>> variants of rti libs. That means if all three are installed I would like to
>>>> find all of them and have them all available within the same applications
>>>> build system.
>>>
>>> Yes.
>>>
>>> find_package(RTI)
>>>    would find all of them 1.3, 1516 and 1516e (which is 1516-2010 right?)
>>>    This would define
>>>       RTI13_FOUND if 1.3 compliant RTI is found
>>>       RTI1516_FOUND if 1516 compliant RTI is found
>>>       RTI1516e_FOUND ...
>>
>> Due to [1], the variables should ne named RTI_RTI{13,1516{,e}}_FOUND,
>> i.e. <PACKAGE>_<COMPONENT>_FOUND. However, there might be a problem
>> with the RTI_FOUND variable regarding backwards compatibility: Since
>> FIND_PACKAGE(RTI) - without specification of any components - should
>> behave the same with the current single-component FindRTI.cmake as
>> well as with a future multi-component one, RTI_FOUND must be FALSE
>> even if a 1516 implementation is detected, i.e. RTI_FOUND does not
>> indicate an 1516 package's presence if FIND_PACKAGE(RTI) is invoked
>> without components. This might be surprising at first glance, but is
>> a particular problem when a single-component find module is advanced
>> towards multiple components. A possible conceptual solution could be:
>>
>> - FIND_PACKAGE(RTI ...) must never run into config mode so that the
>>  FindRTI.cmake module retains control of the RTI_FOUND variable; a
>>  config file would mean that RTI_FOUND is forcedly set to TRUE.
>>  Since the diverse RTI packages stem from different projects,
>>  this should be well feasible.
>> - Calling FIND_PACKAGE(RTI) without components mimics the current
>>  behavior, i.e. only a 1.3 package is searched, the variables are
>>  set up like the single-component FindRTI.cmake does it now, and
>>  RTI_FOUND just indicates the presence of a 1.3 package even if
>>  a 1516 package is available on the system.
>> - Calling FIND_PACKAGE(RTI COMPONENTS HLA13) basically does the same,
>>  but behaves as expected for a component-aware find module, i.e. it
>>  also looks for a 1.3 package only, but sets up the variables right
>>  in a multi-component manner: RTI_HLA13_{FOUND,LIBRARY,INCLUDE_DIR}.
>>  RTI_FOUND indicates whether anything about RTI has been detected;
>>  actually, this merely means that the component-specific *_*_FOUND
>>  variables have received defined values, possibly even limited to
>>  the components explicitly requested via the FIND_PACKAGE() call.
>>
>> Anyway, a multi-component FindRTI.cmake is the way to go, IMO, and
>> should be strongly preferred to the addition of any further find
>> modules which are closely related and differ just slightly.an
> 
> Hi Michael,
> 
> Thank you for this thorough explanation as usual.
> I'll try to stick to the referenced Module coding guidelines you've just
> described.
> 
>>>> Is this possible to implement this within a single find_package call?
>>>
>>> This is possible as long as the resulting variables are separate.
>>> (in our case there is some RTIxxx prefix)
>>
>> Note that there may be difficiulties w.r.t. possible prerequisites in
>> this way: The *_*_{LIBRARY,INCLUDE_DIR} variables contain information
>> about the related component only, i.e. without prerequisite libraries
>> and include directories. The full information is provided by the non-
>> cached component-unspecific *_{LIBRARIES,INCLUDE_DIRS} variables, i.e.
>>
>> FIND_PACKAGE(RTI COMPONENTS HLA13 RTI1516 RTI1516E)
>>
>> would return RTI_{LIBRARIES,INCLUDE_DIRS} suitable to use the HLA13
>> and RTI1516 and RTI1516E components in the same target,
> 
> This requirement is problematic because RTI1516 and RTI1516E
> do have the same library names (but not the same path of course).

AFAICS from Mathias' FindRTI1516{,E}.cmake modules, the libraries have
different names, but their respective header files are named the same:

FIND_LIBRARY(RTI1516_LIBRARY  NAMES rti1516  RTI1516 ...)
FIND_LIBRARY(RTI1516E_LIBRARY NAMES rti1516e RTI1516E ...)

FIND_PATH(RTI1516_INCLUDE_DIR  NAMES RTI/RTI1516.h ...)
FIND_PATH(RTI1516E_INCLUDE_DIR NAMES RTI/RTI1516.h ...)

Therefore, the usage of both libraries for the same binary should be
quite possible as long as they don't violate the one-definition-rule,
whereas the inclusion of both headers for the same compilation unit
will require some trickery, e.g. an intermediate header containing
configured #include directives with the other headers' full paths.

>> whereas the
>> RTI_*_{LIBRARY,INCLUDE_DIR} variables don't comprise the respective
>> component's possible prerequisites.
> 
> Why wouldn't they?
> FIND_PACKAGE(RTI COMPONENTS HLA13 RTI1516 RTI1516E)
> 
> should set
> RTI_*_{LIBRARY,INCLUDE_DIR}

Yes, it does, but these singular-named variables are typically the
results of FIND_PATH() and FIND_LIBRARY(), i.e. they contain just a
single path that's also meant to be presettable in the cache by the
user. So, linking against ${RTI_<COMPONENT>_LIBRARY} will fail once
the component's library needs a prerequisite one. Rather, it's the
job of the <PACKAGE>_LIBRARIES variable to provide a full set of
libraries - the package's ones as well as their prerequisites -
in order to successfully link a binary.

>> Thus, in order to use one of the
>> required components separately from the others, one can rely neither
>> on RTI_{LIBRARIES,INCLUDE_DIRS} nor on RTI_*_{LIBRARY,INCLUDE_DIR}.
>> Instead, one should use multiple FIND_PACKAGE() calls and save
>> their results immediately:
>>
>> FIND_PACKAGE(RTI COMPONENTS HLA13)
>> SET(HLA13_LIBRARIES ${RTI_LIBRARIES})
>> SET(HLA13_INCLUDE_DIRS ${RTI_INCLUDE_DIRS})
>>
>> FIND_PACKAGE(RTI COMPONENTS RTI1516)
>> SET(RTI1516_LIBRARIES ${RTI_LIBRARIES})
>> SET(RTI1516_INCLUDE_DIRS ${RTI_INCLUDE_DIRS})
>>
>> FIND_PACKAGE(RTI COMPONENTS RTI1516E)
>> SET(RTI1516E_LIBRARIES ${RTI_LIBRARIES})
>> SET(RTI1516E_INCLUDE_DIRS ${RTI_INCLUDE_DIRS})
>>
>> In other words: A multi-component FIND_PACKAGE() possibly needs to be
>> called multiple times, each time with the set of components you intend
>> to use collectively. BTW, this is one of the reasons why I am strongly
>> in favor of FIND_PACKAGE() not accumulating results, i.e. the results/
>> effects of a FIND_PACKAGE() call should not depend on the results/
>> effects of a previous call in the same scope, cf. FindQt4.cmake.
> 
> I see but could not understand why
> 
> FIND_PACKAGE(RTI COMPONENTS HLA13 RTI1516 RTI1516E)
> SET(HLA13_LIBRARIES ${RTI_HLA13_LIBRARIES})
> SET(HLA13_INCLUDE_DIRS ${RTI_HLA13_INCLUDE_DIRS})
> SET(RTI1516_LIBRARIES ${RTI_RTI1516_LIBRARIES})
> SET(RTI1516_INCLUDE_DIRS ${RTI_RTI1516_INCLUDE_DIRS})
> ...
> 
> wouldn't work?
> Or why couldn't we use RTI_*_INCLUDE_DIRS and alike directly?

Such component-specific plural-named variables are not explicitly
mentioned in [1]. Of course, one could introduce them, so to say
as obvious enhancements, but the relations among the components
of a package might be so subtle that their benefit is doubtful:

Imagine a package X with components A and B. The latters can be used
together, but in that case, A's header A.h needs to be compiled with
-DX_WITH_B. Please don't ask for a concrete example as I don't know
any, but I wouldn't rely on the assumption that something like this
will never happen. Where is FindX.cmake to put -DX_WITH_B? A natural
choice would be a component-specific X_A_DEFINITIONS variable alike
the component-specific X_A_{LIBRARIES,INCLUDE_DIRS}, but what if the
user intends to use A and B in different targets and just requested
them in a single FIND_PACKAGE() call? In this case, X_A_DEFINITIONS
would contain -DX_WITH_B although A is not to be used with B in the
same binary.

In other words: The content of such, say, full-featured variables like
RTI_*_{LIBRARIES,INCLUDE_DIRS} might need to be modified according to
whether the respective component is used with other components for the
same target or not, but this information is usually not available for
FIND_PACKAGE(). So, I think it's best to not introduce such variables
and agree on the meaning of RTI_{LIBRARIES,INCLUDE_DIRS,...} instead:
RTI_LIBRARIES contains *exactly* what's necessary to link against the
components requested in the FIND_PACKAGE() call, no more, no less, and
the same holds for RTI_{INCLUDE_DIRS,DEFINITIONS}. IMO, that's the only
bullet-proof way to ensure that binaries can be built properly without
the danger of being overlinked or the like, even if this might require
multiple FIND_PACKAGE() invocations, and a find module or config file
is perfectly suited to take arbitrary inter-component relations into
account.

An example for the opposite:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(XMLSQL CXX)
SET(CMAKE_VERBOSE_MAKEFILE ON)

FIND_PACKAGE(Qt4 COMPONENTS QtXml)
INCLUDE(${QT_USE_FILE})
FILE(WRITE ${CMAKE_BINARY_DIR}/xml.cxx "int main(void){return 0;}\n")
ADD_EXECUTABLE(xml xml.cxx)
TARGET_LINK_LIBRARIES(xml ${QT_LIBRARIES})

FIND_PACKAGE(Qt4 COMPONENTS QtSql)
INCLUDE(${QT_USE_FILE})
FILE(WRITE ${CMAKE_BINARY_DIR}/sql.cxx "int main(void){return 0;}\n")
ADD_EXECUTABLE(sql sql.cxx)
TARGET_LINK_LIBRARIES(sql ${QT_LIBRARIES})

As you will see, "xml" is linked correctly, but "sql" is linked against
QtXml, too, and both are compiled with -DQT_XML_LIB *and* -DQT_SQL_LIB.
That's because FindQt4.cmake has a memory - the QT_USE_QT* variables -
and UseQt4.cmake - necessary to populate the QT_LIBRARIES variable -
modifies the compilation environment. What I'd like to do instead
is roughly

FIND_PACKAGE(Qt4 COMPONENTS QtXml)
SET(XML_LIBRARIES ${QT_LIBRARIES})
...
TARGET_LINK_LIBRARIES(xml ${XML_LIBRARIES})

FIND_PACKAGE(Qt4 COMPONENTS QtSql)
SET(SQL_LIBRARIES ${QT_LIBRARIES})
...
TARGET_LINK_LIBRARIES(sql ${SQL_LIBRARIES})

but AFAIK, that's currently impossible unless one sets/unsets the
QT_USE_QT* variables before including UseQt4.cmake, and even this
wouldn't roll back the ADD_DEFINITIONS() commands. IMO, building
more than one Qt-dependent target with different requirements
cleanly within the same scope is not straight forward, ATM.

Regards,

Michael

>>>>> I'll help to review and test the module (at least on Linux).
>>
>> FindRTI1516{,E}.cmake's quick review has drawn my attention to the
>> invocations of CHECK_CXX_SOURCE_COMPILES() used to distinguish the
>> 1516{,E} libraries: IMO, one should be prepared that FIND_PACKAGE()
>> isn't called for the usual purposes; perhaps, the results are to be
>> used just for documentation or a textual analysis of a header file
>> or whatever. Thus, one should not rely on the assumption that FIND_
>> PACKAGE() is called from within a setup that allows the compilation
>> of anything; rather, CHECK_CXX_SOURCE_COMPILES() or another command/
>> function that executes a program is quite critical in a find module.
> 
> True, may even be worse if trying to cross-compile.
> 
>> At least, such checks should be protected by a variable, i.e. they
>> are performed solely with the user's agreement, or implemented as
>> supplementary functions, e.g. CHECK_RTI1516{,E}_SOURCE_COMPILES().
> 
> Agreed.
> I'll check but I think the main difference between 1516 (a.k.a. 1516-2000) and
> 1516e (a.k.a. 1516-2010) is the namespace 1516e instead of 1516
> so FILE(READ ...)  + REGEX for 1516e inside RTI/RTI1516.h should be enough.
> 
> see:
> http://standards.ieee.org/downloads/1516/1516.1-2010/
> 
>> [1] ${CMAKE_ROOT}/Modules/readme.txt
> 
> I'll check that.
> 
> --
> Erk
> Membre de l'April - « promouvoir et défendre le logiciel libre » -
> http://www.april.org


More information about the CMake mailing list