1

I have a specific question which serves as context for a more general question.

There is a scientific package called LAMMPS, and it is usually used as an executable. However, it supports use as a "library". To try to do things right, I put it in /usr/local/lib/lammps. It contains a lammps/src/ directory, which has around 40 source files. Using the instructions provided, I compiled lammps as a .so file in lammps/src/liblammps_serial.so.

I also have separate code in "~/code/ljtube/". This uses cmake to try to find the library. Thus, I wrote a FindLAMMPS.txt so that I could use

FIND_PACKAGE (lammps)

in my CMakeLists. I modified the libtool config file to search in /usr/local/ successfully. I found that it searches in /usr/local/lib/ for a .so file and in /usr/local/include/ for a .h file. So I made a dynamic link to the .so file in /usr/local/lib/, and I copied the .h file from the lammps/src/ to /usr/local/include/.

CMake can now find those two files, but it cannot link to anything else in lammps/src/. It seems absurd to need to make a separate FIND_PACKAGE for each of the .h's I want to include (group.h, fix.h, force.h, pair.h, etc.). It also seems ridiculous to dump the whole package of .h files into the /usr/local/include/ directory. I will be using this code both locally and on a cluster, and possibly distributing it to other group members.

How can I make CMake find what I want to find without hard coding in the location of /usr/local/lib/lammps/src/? Phrased more generically, how should I manage large packages like these to make them easy to link to in the code I write, even if the original developer did not use the best conventions?

(As a side note, I am using a shared library because it seems like the right choice, but I'm not especially married to it. Should I be using a static library? Is there a way for CMake to find an already-compiled library relative to the current source directory, and might that be a better way to implement this? I know that I will be using LAMMPS in multiple projects, so having a local shared copy superficially seems to make the most sense.)

Zulu
  • 8,765
  • 9
  • 49
  • 56
John Haberstroh
  • 465
  • 4
  • 11

1 Answers1

1

Normally a find_package call yields a variable specifying the path to the "includes" folder of the package. This would then be added in the caller's CMakeLists.txt via include_directories.

For example, to use find_package for boost, you could do:

find_package(Boost)  # sets ${Boost_INCLUDE_DIRS} and ${Boost_LIBRARIES}
if(Boost_FOUND)
  include_directories(${Boost_INCLUDE_DIRS})
  add_executable(foo foo.cc)
  target_link_libraries(foo ${Boost_LIBRARIES})
endif()


Regarding your side note, you could use find_library and/or find_path to find the library and its headers given a known location.

Both these commands can be invoked in such a way as to avoid searching in common locations, e.g. by setting PATHS to the known location and using NO_DEFAULT_PATH in the find commands.

Another alternative is for your projects to make use of the ExternalProject_Add function which is described in more detail in this article. From this article:

The ExternalProject_Add function makes it possible to say “download this project from the internet, run its configure step, build it and install it”

A downside to this approach is that each of your projects would end up with its own copy of the third party sources and lib.

Fraser
  • 74,704
  • 20
  • 238
  • 215
  • That's definitely half of the answer. A big part of my question is **how** to coax cmake into finding all of the files _in the common locations_; cmake won't look inside lammps/src/ for the .h files. Surely some distributed software has many .h files that must be referenced, and they don't all go in /usr/include/! Also, that ExternalProject_Add is awesome, good find. – John Haberstroh Jan 02 '13 at 03:25
  • Glad the answer's of some use. As far as finding headers, I'd expect all headers which need to be available to external users to be in a single "includes" folder. This single root could be in /usr/include/, but then users only need to find that one folder. If there are subdirs of that, they should be reflected in the #include statements of the user's code, but ultimately there's just one "includes" folder. All other headers scattered about source folders should not be required by users of the library. – Fraser Jan 02 '13 at 13:11