On Fri, May 29, 2009 at 5:48 AM, Clinton Stimpson
<[email protected] <mailto:[email protected]>> wrote:
Jed Brown wrote:
Alexander Neundorf wrote:
On Monday 25 May 2009, Jed Brown wrote:
Bill Hoffman wrote:
You can also set QMake on the cmake command line
as well:
cmake -DQT_QMAKE_EXECUTABLE=/path/to/qmake ../source
Yeah, I'm much less concerned with this particular
case as with the
philosophy that the correct way to select
installations is by modifying
PATH. Frustratingly, a new user will fire up cmake
and get the wrong
version (they're not even aware of exactly what the
dependencies are,
let alone the naming convention for the cache variable
that will get the
correct version). So they interactively change a
couple paths and
reconfigure. Lo and behold, they now have an
inconsistent state because
the cache wasn't flushed when they changed
QT_QMAKE_EXECUTABLE (I don't
know if this is the case with Qt, but is is with most
packages).
...
Using PATH and falling back on peculiarly named
variables (hopefully
only one non-advanced variable per package, so that
it's unambiguous)
With the new cmake-gui this is now much easier :-)
CMake gui is nice and it's easier to edit variables. For this
case, I
think the only way it makes a difference is that you can go to
advanced
grouped mode and wipe out a whole group easily. Some packages
have
dependencies, so this isn't a complete solution, but it does
make a big
difference. I wrote the following before noticing that it was
easy to
clear groups, but I think it's still somewhat relevant.
The user doesn't know the name of special variables (like
QT_QMAKE_EXECUTABLE) until they press Configure. If the wrong
version
is found on the first pass, it's typically too late to change
the path.
(There isn't a concept of dependent cache variables so very
few Find*
modules can clean up after an incorrect version is found.
There is an
implicit assumpition that if *any* installation is found, it
is the one
the user wanted. FindQt4 might be a very rare exception to
this. I
haven't tested its robustness since I don't use it, but I see
a lot of
QT_QMAKE_CHANGED logic so the author is at least trying to
handle this.)
So they have to flush the cache and define the special
variable *before*
CMake shows them that the variable exists. Until packages can
robustly
support changing their path *after* the first pass finds an
undesired
version, I think that recognizing semi-standard environment
variables
like QTDIR would be good policy (e.g. the user is much more
likely to
guess QTDIR than QT_QMAKE_EXECUTABLE if they are unfamiliar
with CMake
and only know that the your package needs Qt).
I don't think of QTDIR as anything of a standard anymore. It was
necessary in Qt3 to make the qmake build system work.
Anyway... read below.
Also, instead of setting PATH to /opt/qt-a.b.c/bin/ you
can also set CMAKE_PREFIX_PATH to /opt/qt-a.b.c/, also to
a list of directories, which cmake will search in the
order you specified.
I know about these, but they have global scope and are thus not a
solution to the problem I stated. You need to be able to specify
install paths *independently*. As a concrete example, suppose
different
versions of MPI are installed at /usr and /usr/local. Similarly,
suppose different versions of Qt are installed at /usr and
/usr/local.
I'm not claiming this is the best organization, but it's not
terribly
uncommon or pathological, so some users will have this
situation and
it's none of our business to tell them to reinstall just to
build our
package.
Qt and MPI are independent packages so their selection cannot be
dependent. Modifying variables like PATH or CMAKE_PREFIX_PATH
will
choose versions for both of these packages. FindMPI.cmake
cannot be set
independently, so if I wanted to get MPI from /usr, I have to
put /usr
first in PATH/CMAKE_PREFIX_PATH. A new user will not know this in
advance. To get Qt from /usr/local, I can set
QT_QMAKE_EXECUTABLE, but
a new user won't know this before running CMake (gui) and
looking at the
options. If they are lucky, they will get the correct MPI on
the first
pass, and although the incorrect Qt is found, they can change
QT_QMAKE_EXECUTABLE and the QT_QMAKE_CHANGED logic will work
correctly
to give them a consistent build. If the wrong MPI is found,
they have
no choice but to delete the cache, modify some global state
(PATH or
similar) and try again. Note that very few Find* modules can
recover
from finding an incorrect package (it takes a lot of work, you
basically
have to work around the cache). In addition, not many have a
single
variable to control which installation is found, thus
necessitating
global control which creates the locking problem.
I think what is being asked here is a good idea.
There is already the CMAKE_PREFIX_PATH which gives
find_package(Qt4) a prefix to work from.
If I set it to one of my other Qt4, directories, it finds that Qt
installation fine.
But maybe adding something like a
QT4_PREFIX_PATH to have find_package(Qt4) prefer another directory
first
and
MPI_PREFIX_PATH to have find_package(MPI) prefer yet a different
directory
would be nice.
Maybe even extend that so if one did
find_program(MYVAR_EXECUTABLE ...)
find_library(MYVAR_LIBRARY ...)
a user of a CMakeLists.txt file containing that could set
MYVAR_PREFIX_PATH.
Or maybe use MYVAR_DIR so the same variable works when cmake
config files are found by find_package().
Maybe another step would be to detect if MYVAR_DIR changed, and
remove all dependent variables and do a re-find.
I see that FindBoost.cmake has a BOOST_ROOT that tries to do the
above, but a standard mechanism for all find_* would be better.
Or does cmake already have a standard way of doing this?
This link [1] suggests that the correct name for the variable should
be QT$_ROOT_DIR (instead of QT4_PREFIX_PATH or QT4_ROOT)
[1]
http://public.kitware.com/cgi-bin/viewcvs.cgi/Modules/readme.txt?root=CMake&view=markup
<http://public.kitware.com/cgi-bin/viewcvs.cgi/Modules/readme.txt?root=CMake&view=markup>
I do something like this when looking for simple packages (thanks to
Greg Peele for a cool tip on this):
# Get hint from environment variable (if any)
if(DEFINED ENV{FOO_ROOT_DIR})
set(FOO_ROOT_DIR "$ENV{FOO_ROOT_DIR}" CACHE PATH "FOO base directory
location (optional, used for nonstandard installation paths)" FORCE)
mark_as_advanced(FOO_ROOT_DIR)
endif()
# Search path for nonstandard locations
if(FOO_ROOT_DIR)
set(FOO_INCLUDE_PATH PATHS ${FOO_ROOT_DIR}/include NO_DEFAULT_PATH)
set(FOO_LIBRARY_PATH PATHS ${FOO_ROOT_DIR}/lib NO_DEFAULT_PATH)
endif()
# Find headers and libraries
find_path(FOO_INCLUDE_DIR NAMES foo/FOO.h ${FOO_INCLUDE_PATH})
find_library(FOO_LIBRARY NAMES FOO ${FOO_LIBRARY_PATH})
... then you can use FindPackageHandleStandardArgs or whatever you
like the most.
I know that FindQT4 is a _lot_ more complicated than this, but anyway,
I find the FOO_ROOT_DIR (env. or cmake) variable very useful.