Menu

#21 Findtclap.cmake available if you want it

Unknown
open
cmake (1)
5
2021-03-24
2018-11-30
No

Hey there! I love TCLAP, been using it for a while. I have a pretty clean find module for CMake if you would like it, maybe just share as a supplemental document on the website? I think if we were to install a "proper" cmake support for tclap, it would be better to avoid Find module but instead install file $prefix/lib/cmake/tclap/tclap-config.cmake, but i don't know how to coordinate that with autotools or honestly if that is even the best approach. Find modules are supposed to be turning into a thing of the past ;)

I was cleaning up some code and realized i need to attach a license to this file, I was just gonna CC0 it but if you want to "formally" adopt it then it's yours and we can make it MIT license same as project :)

# Findtclap.cmake
#
# A simple Find module for `find_package(tclap)`, for the TCLAP project:
#
#     http://tclap.sourceforge.net/
#
# This Find module respects ``${tclap_ROOT}`` and ``$ENV{tclap_ROOT}`` variables.  See
# CMake Policy CMP0074 for more information.
#
# The following variables are set:
#
# ``tclap_FOUND``
#     ``TRUE`` if package was found, ``FALSE`` if not found.
#
# ``tclap_INCLUDE_DIR``
#     The include directory if needed.  Only set if ``tclap_FOUND``.
#
# If ``tclap_FOUND``, then the imported interface library ``tclap::tclap`` is created
# with the appropriate include directory.  Example usage:
#
# .. code-block:: cmake
#
#     find_package(tclap REQUIRED)
#     target_link_libraries(mylib PUBLIC tclap::tclap)
#     # ... or ...
#     target_include_directories(mylib PUBLIC ${tclap_INCLUDE_DIR})
#
# .. warning::
#
#     At least at this time, TCLAP only includes version information in the installed
#     ``pkg-config`` file ``tclap.pc``.  This means that version information cannot
#     be extracted when ``pkg-config`` is not available.  Since TCLAP has a very stable
#     interface, in the event that version information cannot be extracted then
#
#     1. ``find_package(tclap X.Y.Z)`` will warn that no version information was found.
#     2. ``find_package(tclap X.Y.Z EXACT)`` will fail, since no version information was
#        recovered.
#
#     Unless you truly need to force exact version information, it is encouraged to
#     *avoid* using ``EXACT`` in ``find_package`` calls for ``tclap``.
if (POLICY CMP0074)
  cmake_policy(PUSH)
  cmake_policy(SET CMP0074 NEW)
endif()

# tclap uses Autotools and by default will install `tclap.pc`.  Try and use pkg-config
# to find the package details (potentially overidden by `tclap_ROOT` below).
find_package(PkgConfig QUIET)
if (PkgConfig_FOUND)
  pkg_check_modules(pc_tclap QUIET tclap)
  if (pc_tclap_VERSION)
    set(tclap_VERSION ${pc_tclap_VERSION})
  endif()
else()
  set(tclap_VERSION "tclap_VERSION-NOTFOUND")
endif()

# NOTE: order matters, search the `tclap_ROOT` variables first.  That is, `tclap_ROOT`
# takes precedence over any potential results from `pkg-config`.
find_path(
  tclap_INCLUDE_DIR tclap/CmdLine.h
  HINTS ${tclap_ROOT} $ENV{tclap_ROOT} ${pc_tclap_INCLUDE_DIRS}
)

# If tclap/CmdLine.h is not found, `if (tclap_INCLUDE_DIR)` evaluates to FALSE.
if (tclap_INCLUDE_DIR)
  set(tclap_FOUND TRUE)
  add_library(tclap::tclap IMPORTED INTERFACE)
  target_include_directories(tclap::tclap INTERFACE ${tclap_INCLUDE_DIR})
else()
  set(tclap_FOUND FALSE)
  if (tclap_FIND_REQUIRED)
    message(FATAL_ERROR
      "tclap could not be found!  Try setting the environment variable `tclap_ROOT` "
      "such that the file `$tclap_ROOT/tclap/CmdLine.h` can be found."
    )
  endif()
endif()

# Strategy: the tclap API is very stable / does not change often.  Since it is a header
# only library, being able to wield `tclap_ROOT` is very convenient (e.g., Windows users
# who do not want to setup `pkg-config`).  However, tclap only includes version
# information in the `tclap.pc` file.  As such, if tclap_VERSION is not able to be found
#
# - ``find_package(tclap X.Y.Z)`` => warn.
# - ``find_package(tclap X.Y.Z EXACT)`` => fail.
#
# In practice, users should only be doing ``find_package(tclap [REQUIRED] [QUIET])``,
# since enforcing a version constraint is likely not necessary.
if (tclap_FIND_VERSION)
  if (NOT tclap_VERSION)
    if (tclap_FIND_VERSION_EXACT)
      message(FATAL_ERROR
        "EXACT tclap version of ${tclap_FIND_VERSION} requested, but `tclap_VERSION` "
        "was unable to be extracted."
      )
    else()
      message(WARNING
        "tclap_VERSION was unable to be extracted, so it is not guaranteed to match "
        "specified tclap version of ${tclap_FIND_VERSION}"
      )
    endif()
  endif()
endif()

if (POLICY CMP0074)
  cmake_policy(POP)
endif()

People then just need to have Findtclap.cmake locally and do find_package(tclap REQUIRED) for them to use it in CMake. Personally my flow is find_package(tclap QUIET) and if not found locally I use FetchContent (another reason to love TCLAP, so easy xD). The idea is instead of tracking my dependencies in my repo, I try and use it if its already installed otherwise I download it and install it with mine (bundled in a nested directory).

As you can see there is a small hiccup where version numbers are concerned, the only way to "fix" this for non pkg-config findable tclap is to embed it in a header file somewhere (e.g., defining TCLAP_VERSION_MAJOR, TCLAP_VERSION_MINOR, and TCLAP_VERSION_PATCH so that I can parse it with CMake). But this won't be a fix for any existing installations, so the maybe-fail maybe-warn behavior would need to remain.

If this sounds like something you'd like me to document more formally (brief "Using TCLAP with CMake" tutorial type page / section somewhere) I am happy to write it up!

Let me know what your thoughts are, thanks for TCLAP :)

Discussion

  • Daniel Aarno

    Daniel Aarno - 2018-12-04
    • assigned_to: Daniel Aarno
     
  • Daniel Aarno

    Daniel Aarno - 2018-12-04

    Thanks, I'll take a look over the Christmas holidays and see what makes sense. I could imagine including it in a contrib directory.

     
  • Manuel Schmitz

    Manuel Schmitz - 2021-03-24

    Meson is an emerging alternative to CMake, which comes with an easy-to-use dependency management. I am currently providing patches that connect TCLAP to the Meson package ecosystem. These are called "wrap files", which are basically references to the TCLAP source packages. If someone's project depends on TCLAP, then he can simply put that wrapfile into a special subfolder. Meson will then look for an installed version of TCLAP, and, if not found, download and build it.

    Along with the wrap file mentioned above, I am providing a meson.build so that Meson can build TCLAP if necessary. (meson.build contains the build config, very much like CMakeLists.txt) If newer versions of TCLAP contain a CMakeLists.txt, then I could skip that step because Meson can use an existing CMakeLists. (Alternatively, TCLAP could use Meson instead of CMake. Both are easier to maintain than autotools.)

     

Log in to post a comment.