View Issue Details Jump to Notes ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0009090CMakeCTestpublic2009-06-01 16:452010-12-14 18:49
ReporterBill Vodall 
Assigned ToZach Mullen 
PrioritynormalSeveritymajorReproducibilityalways
StatusclosedResolutionfixed 
PlatformOSOS Version
Product VersionCMake-2-6 
Target VersionFixed in VersionCMake-2-8 
Summary0009090: CTest does not handle absolute paths in CTestTestfile SUBDIR( ) entries.
Description
Testing enabled CMake builds where the binary directory is outside of the source tree result in SUBDIR entries in the CTestTestfile.cmake file that have absolute paths. The SUBDIR() handling in CTest always assumes the path is relative thus it fails to find and follow the subdir links with absolute paths.
Additional Information
A small change to ctest/cmCTestTestHandler.cxx appears to have fixed the issue both on Linux and Win32

--- ctest/cmCTestTestHandler.cxx ---

bool cmCTestSubdirCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
{
 ...
 std::vector<std::string>::const_iterator it;
 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
 for ( it = args.begin(); it != args.end(); ++ it )
   {
   cmSystemTools::ChangeDirectory(cwd.c_str());
   std::string fname = cwd;
   fname += "/";
   fname += *it;

* if ( !cmSystemTools::FileIsDirectory(fname.c_str()) )
* {
* fname = *it;
* }

-----

Here is a slightly trimmed copy of Tylers posting to the CMAKE discussion list
documenting how to reproduce this issue.


On Fri, May 29, 2009 at 10:58:50AM -0700, Bill V wrote:
> The subdir code in CMAKE proper (cmSubdirCommand.cxx) has logic to
> handle relative or absolute paths. The subdir handling code in
> CTest/cmCTestTestHandler.cxx always assumes it's a relative path and
> prepends the current directory. Maybe cmCTestTestHandler.cxx needs
> to be updated.


Indeed. After a lot of experimenting, I think I have a small case that
demonstrates the problem.

[tylermr@alta:~/ctest-paths-test2]$ find
.
./module1
./module1/CMakeLists.txt

./module1/module1subdir
./module1/module1subdir/CMakeLists.txt

./module2
./module2/CMakeLists.txt

Module1 is the "main" project. It does add_subdirectory() on module2
(which lives next to it on disk) and module1subdir (which lives
underneath module1 on disk).

The Lists are also simple:

MODULE1
-------
project(module1)
cmake_minimum_required(VERSION 2.6)

enable_testing()

set (PLATFORM "linux")
set (BUILD_TYPE "debug")

# The source path of the subdirectory is relative to the source path of
# this project. The binary path of the subdirectory is relative to the
# *binary* path of this project, hence the extra "../".
add_subdirectory(../module2 ../../module2/${PLATFORM}/${BUILD_TYPE})
add_subdirectory(module1subdir ../module1subdir/${PLATFORM}/${BUILD_TYPE})

MODULE1SUBDIR
-------------
project(module1subdir)
cmake_minimum_required(VERSION 2.6)

add_test (module1subdirtest1 "pwd")

MODULE2
-------
project(module2)
cmake_minimum_required(VERSION 2.6)

add_test (module2test1 "pwd")



So let's do an out-of-source build on this project:

[tylermr@alta:~/ctest-paths-test2/module1]$ mkdir build
[tylermr@alta:~/ctest-paths-test2/module1]$ cd build/
[tylermr@alta:~/ctest-paths-test2/module1/build]$ cmake ..
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/lib64/ccache/gcc
-- Check for working C compiler: /usr/lib64/ccache/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/lib64/ccache/c++
-- Check for working CXX compiler: /usr/lib64/ccache/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to:
/alta/tylermr/ctest-paths-test2/module1/build


And let's inspect the CTestTestfile.cmake which is written out:

[tylermr@alta:~/ctest-paths-test2/module1/build]$ cat CTestTestfile.cmake
# CMake generated Testfile for
# Source directory: /alta/tylermr/ctest-paths-test2/module1
# Build directory: /alta/tylermr/ctest-paths-test2/module1/build
#
# This file replicates the SUBDIRS() and ADD_TEST() commands from the
# source
# tree CMakeLists.txt file, skipping any SUBDIRS() or ADD_TEST()
# commands
# that are excluded by CMake control structures, i.e. IF() commands.
SUBDIRS(/alta/tylermr/ctest-paths-test2/module2/linux/debug)
SUBDIRS(../module1subdir/linux/debug)


Note that module2 is written out with an absolute path while
module1subdir is written out with a relative path. CTest will only work
with the relative path because, as Bill noted, CTest *always* prepends
the current binary directory to the beginning of each path it finds in a
SUBDIRS() command. As a result, CTest can only find one of the test
cases in the project:

[tylermr@alta:~/ctest-paths-test2/module1/build]$ ctest
Start processing tests
Test project /alta/tylermr/ctest-paths-test2/module1/build
 1/ 1 Testing module1subdirtest1 Passed

100% tests passed, 0 tests failed out of 1


Proof of the path prepending can be seen in this excerpt from strace:

[tylermr@alta:~/ctest-paths-test2/module1/build]$ strace ctest
execve("/usr/local/bin/ctest", ["ctest"], [/* 89 vars */]) = 0
[...]
getcwd("/alta/tylermr/ctest-paths-test2/module1/build", 2048) = 46
chdir("/alta/tylermr/ctest-paths-test2/module1/build") = 0
access("/alta/tylermr/ctest-paths-test2/module1/build//alta/tylermr/ctest-paths-test2/module2/linux/debug", R_OK) = -1 ENOENT (No such file or directory)
getcwd("/alta/tylermr/ctest-paths-test2/module1/build", 2048) = 46
chdir("/alta/tylermr/ctest-paths-test2/module1/build") = 0
access("/alta/tylermr/ctest-paths-test2/module1/build/../module1subdir/linux/debug", R_OK) = 0
[...]


I think the this inconsistency stems from some logic in
cmLocalGenerator::ConvertToRelativePath (which is called by
cmLocalGenerator::Convert which is called by
cmLocalGenerator::GenerateTestFiles which is the method that writes out
CTestTestfile.cmake). I haven't read the code too closely but these
comments seem enlightening:

 // Skip conversion if the path and local are not both in the source
 // or both in the binary tree.

and

 // If no part of the path is in common then return the full path.


I believe there is a bug in CTest's SUBDIRS() command. It should accept
absolute paths, like add_subdirectory() does.

...

Btw, there is a discrepancy between how subdirs works in CTest vs how it
works in CMake. Compare CTest/cmCTestTestHandler::cmCTestSubdirCommand
with cmSubdirCommand::cmSubdirCommand.

The one for CMake has some logic that checks if
Makefile->GetCurrentDirectory/directory_from_subdir_command points
somewhere useful. If it does, cmSubdirCommand adds the directory with
the prepended current directory. (If not, it returns
directory_from_subdir_command undecorated.)

cmCTestSubdirCommand doesn't have this logic; it always prepends
GetCurrentWorkingDirectory() with no tests to make sure the resulting
decorated directory exists on the filesystem.


Thanks,
tyler
TagsNo tags attached.
Attached Files

 Relationships

  Notes
(0018371)
Zach Mullen (developer)
2009-11-09 14:10

I just committed your patch. Thanks =)
(0024070)
David Cole (manager)
2010-12-14 18:49

Closing bugs that have been resolved for more than 3 months without any further updates.

 Issue History
Date Modified Username Field Change
2009-06-01 16:45 Bill Vodall New Issue
2009-09-30 09:54 Bill Hoffman Status new => assigned
2009-09-30 09:54 Bill Hoffman Assigned To => Zach Mullen
2009-11-09 14:10 Zach Mullen Note Added: 0018371
2009-11-24 14:25 Zach Mullen Status assigned => resolved
2009-11-24 14:25 Zach Mullen Fixed in Version => CMake-2-8
2009-11-24 14:25 Zach Mullen Resolution open => fixed
2010-12-14 18:49 David Cole Note Added: 0024070
2010-12-14 18:49 David Cole Status resolved => closed


Copyright © 2000 - 2018 MantisBT Team