[vtk-developers] New VTK directory structure and build process (bug fix).

Sebastien BARRE seb-ml-vtk at barre.nom.fr
Mon May 7 23:08:35 EDT 2001


Hi

Here is some more feedback. More bugs were found (or maybe design flaws... 
or just "features" :) ?). Some were fixed. Nothing was committed to the 
CVS. Please tell me what do you want me to commit (including the previous 
email).

Once again, the new tree is very nice :), and cmake looks promising. Great 
work.

Windows build :
My conf :
	- Windows 2000 SP1 (Athlon 800 MHz, 300 RAM)
	- Tcl 8.3
	- Python 2.0
	- Microsoft Visual C++ 6

VTK_USE_PARALLEL  and VTK_WRAP_JAVA were OFF. Everything else was "ON".

Cmake:
________
cmake*.exe was not found. I had to build the proper targets. No problem. Is 
cmake*.exe going to be included in the source distrib (and CVS) like 
pcmaker is ?
Note : it would be cool if the Cmake GUI could remember the path chosen in 
the "Open File" dialog box.


The Build :
________
I generated the according MSVC++ DSP files, and started building VTK.

BTW, what's the difference between the "Release" and "Release MinSize" 
settings ?

"Accidently" I forgot to set the BUILD_SHARED_LIBS flag => when I started 
MSVC, the default target was "ALL_BUILD - Win32 Release MinSize" (the two 
others were "ALL_BUILD - Win32 Debug" and "ALL_BUILD - Win32 Release"), 
which looked fine because there was a "Win32 Release MinSize" setting for 
all subtargets (Common, Filtering, Imaging, etc).

The build ran fin... but I was unable to find the .dll files.

Then I remembered how stupid I was and set BUILD_SHARED_LIBS to "On" => 
when I started MSVC again, it complained because the default target was 
still "ALL_BUILD - Win32 Release MinSize" but there was *no* "Win32 Release 
MinSize" setting anymore for the subtargets :(. Thus, I had to switch to 
"Release"... and rebuild everything again :(

It failed on the first lib :

******************************
Linking...
    Creating library Release/vtkCommon.lib and object Release/vtkCommon.exp
vtkOutputWindow.obj : error LNK2001: unresolved external symbol "public: 
virtual void __thiscall vtkWin32OutputWindow::DisplayText(char const *)" 
(?DisplayText at vtkWin32OutputWindow@@UAEXPBD at Z)
vtkOutputWindow.obj : error LNK2001: unresolved external symbol "public: 
static class vtkWin32OutputWindow * __cdecl 
vtkWin32OutputWindow::New(void)" (?New at vtkWin32OutputWindow@@SAPAV1 at XZ)
Release/vtkCommon.dll : fatal error LNK1120: 2 unresolved externals
******************************

Indeed vtkWin32OutputWindow  was *not* compiled. I checked 
vtknew/Common/CMakeLists.txt and found :

IF (WIN32)
   SOURCE_FILES(LIBRARY_SRCS vtkWin32OutputWindow)
ENDIF (WIN32)

BUG : it has to be changed to :

IF (WIN32)
   SOURCE_FILES(Common_SRCS vtkWin32OutputWindow)
ENDIF (WIN32)

... which solved that problem (already posted in my previous email).

The rest of the build worked fine.

Problem : at the end of the build, there was no single directory were the 
DLLs could be found : each DLL file was stored in a different directory 
(e.g., $BUILD_DIR/Common/Release, $BUILD_DIR/Filtering/Release, 
$BUILD_DIR/Graphics/Release). This is a bit problematic as it implies that 
each directory should be added to the PATH environment variable in order 
the DLL to be found by the system. Nevertheless, I noticed that there is an 
empty $BUILD_DIR/Release directory : I guess it would be good if all DLL 
files were moved to this directory. This step might just be missing from 
the correct Cmake configuration. I moved the DLLs manually, and added 
$BUILD_DIR/Release to the PATH.

Note : I think a $BUILDIR/Lib/Release directory would be better, because 
all builds (Release, Debug, Release MinSize) could be located under the 
same $BUILDIR/Lib directory : less clutter.

Note : I could not find any settings to trigger a non-incremental build 
(i.e. no single big vtkdll.dll file).


Tcl  :
________
If VTK_USE_RENDERING is "On", then Cmake requires the internal path to 
tkWinInt.h. The bundled file is v1.4. Mine is 1.7. Anyway, I tried with 
mine (thus, overriding the TK_INTERNAL_PATH cache value, which was properly 
found in the new tree anyway).

Correct me if I'm wrong, but it looks to me that all .cxx files are first 
parsed/wrapped, then compiled (instead of being "parsed + compiled" one by 
one).

The build failed :

******************************
Linking...
    Creating library Release/vtkCommonTCL.lib and object 
Release/vtkCommonTCL.exp
vtkTclUtil.obj : error LNK2001: unresolved external symbol 
__imp__Tcl_DeleteCommand
vtkWindowLevelLookupTableTcl.obj : error LNK2001: unresolved external 
symbol __imp__Tcl_DeleteCommand
[...]
Release/vtkCommonTCL.dll : fatal error LNK1120: 16 unresolved externals
Error executing link.exe.

ALL_BUILD - 737 error(s), 7 warning(s)
******************************

OK, this one is tricky. I might be completely wrong, but this is either a 
bug or a design flaw. The Cmake documentation is a bit small at the moment 
to understand every details.

Obviously, the previous step could not complete because the Tcl/Tk libs 
were not linked.

Thus, I had a look at vtknew/CMakeLists.txt, and found that :

[...]
#
# get information for Tcl wrapping
#
OPTION(VTK_WRAP_TCL "wrap classes into the TCL intepreted language")
IF (VTK_WRAP_TCL)
   INCLUDE (${CMAKE_SOURCE_DIR}/CMake/Modules/FindTCL.cmake)

   # add in the Tcl values if found
   IF (TCL_INCLUDE_PATH)
     INCLUDE_DIRECTORIES(${TCL_INCLUDE_PATH})
   ENDIF (TCL_INCLUDE_PATH)
   IF (TCL_LIB_PATH)
     LINK_DIRECTORIES (${TCL_LIB_PATH})
   ENDIF (TCL_LIB_PATH)
   IF (TCL_LIBRARY)
     LINK_LIBRARIES (${TCL_LIBRARY})
   ENDIF (TCL_LIBRARY)
[...]

Here we are. The Tcl lib is added to the link list only if the TCL_LIBRARY 
variable is set.
When is it set ? In a single file (i.e. Cmake module), 
vtknew\CMake\Modules\FindTCL.cmake, where there are blocks responsible for 
detecting Tcl (or Tk) :

IF (NOT TCL_LIB_PATH)
   FIND_LIBRARY(TCL_LIB_PATH tcl82 "C:/Program Files/Tcl/lib" /usr/lib 
/usr/local/lib)
   IF (TCL_LIB_PATH)
     SET (TCL_LIBRARY tcl82 CACHE)
   ENDIF (TCL_LIB_PATH)
ENDIF (NOT TCL_LIB_PATH)

Check the SET (TCL_LIBRARY tcl82 CACHE) line, which sets TCL_LIBRARY to 
tcl82, and puts the value in the cache ($BUILDIR/CMakeCache.txt).

Two problems :

a) the Tcl/Tk version is hardcoded. To my opinion, this is bad :) In 
pcmaker, we (well, mainly I, at the end :) tried to avoid that by asking 
the user to enter the *full pathname* to the library (ex: 
somepath/tclXX.lib). Then we found the version by extracting the 'XX' 
string from the pathname. Hardcoding the version in Cmake means :
	- the current Cmake obviously don't work with Tcl 8.3 (which has been a 
user request for a long time :),
	- the FindTcl.cmake file must be updated every time a new version major or 
minor of Tcl arises :(,
	- we must include all possible major+minor library versions :((, which 
looks problematic to my knowledge, and I guess it is not specific to this rule.

Am I wrong ? I should add that I'm not familiar with Cmake at the moment.

b) I tried to solve the problem simply by adding a new block for the 8.3 
version :

IF (NOT TCL_LIB_PATH)
   FIND_LIBRARY(TCL_LIB_PATH tcl83 "C:/Program Files/Tcl/lib" /usr/lib 
/usr/local/lib)
   IF (TCL_LIB_PATH)
     SET (TCL_LIBRARY tcl83 CACHE)
   ENDIF (TCL_LIB_PATH)
ENDIF (NOT TCL_LIB_PATH)

This failed, for the following reason : the

   IF (TCL_LIB_PATH)
     SET (TCL_LIBRARY tcl83 CACHE)
   ENDIF (TCL_LIB_PATH)

code is only executed (interpreted) if the test 'IF (NOT TCL_LIB_PATH)' is 
true :(, this means that if TCL_LIB_PATH is manually set, it will never be 
executed. And it is my case : my Tcl is not installed in a usual directory, 
thus I *had* to set it manually in the Cmake GUI. As soon as I did that, 
the test was false, and the TCL_LIBRARY was never set to a proper value (it 
remains unset and does not appear in the cache file). Thus, the Tcl library 
was not added to the link list :(

Nevertheless, I replaced the above code by :

IF (NOT TCL_LIB_PATH)
   FIND_LIBRARY(TCL_LIB_PATH tcl83 "C:/Program Files/Tcl/lib" /usr/lib 
/usr/local/lib)
ENDIF (NOT TCL_LIB_PATH)

IF (TCL_LIB_PATH)
   SET (TCL_LIBRARY tcl83 CACHE)
ENDIF (TCL_LIB_PATH)

...rejecting the inner test outside the 'IF (NOT TCL_LIB_PATH)'.

This works, but of course this is NOT the right solution. The fact that 
TCL_LIB_PATH is set does not mean that it is set to a 8.3 version at the 
moment. Anyway, I needed the TCL_LIBRARY variable to be set in the cache, 
hence this workaround is OK at the moment (albeit stupid :).

I do not know anything about Cmake, hence I'm unable to suggest anything to 
the CMake gurus :) I guess asking for a '*full pathname* to the lib' 
instead of the 'pathname to the directory holding the lib' could help : if 
there is some pattern-matching capabilities built into Cmake we could then 
find the 'XX' version in 'somepath/tclXX.lib'.

Of course, same goes for Tk in FindTCL.cmake.

Good think, the Tk Render widgets are built correctly.


Python:
________
Cmake asks for the path to Python 2.1 lib :( Well, I know we all have been 
asking for Python 2.x (did we ?), but isn't Python 2.1 not a bit too 
"young" ? I mean, the official 2.1 release was 3 weeks ago... There is a 
risk that important modules might not have been rebuilt/ported to Python 
2.1 yet. For example, PyOpenGL has not. Yes I know, It's a piece of 
cake  to rebuild...but if I do not want to rebuild all my modules at the 
moment :)

This would not have been a problem if, like pcmaker, Cmake would allow me 
to use whatever version of Python. I did not find a way to achieve this : 
once again (see Tcl above), it seems that the "Python 2.1" setting is 
hardcoded. More seriously, not only is it hardcoded, but it's hardcoded in 
each and every CMakeList.txt file, instead of being hardcoded in a single 
Cmake rule (like FindTCL.cmake). I do not worry about that, I'm quite sure 
CMake will include this feature soon or later, am I right ? ;) I guess it 
would be very good if we could use at least whatever *minor* version of Python.

Moreover, it makes no sense to use Python 2.1 if the Tcl lib is < 8.3 (this 
won't work). And as reported above, Tcl 8.3 is not supported by CMake at 
the moment.

OK, I had to patch each CMakeLists.txt file, and replace all python21 
strings with python20 (20 items replaced in 10 files).

The link failed :

******************************
Linking...
    Creating library Release/vtkFilteringPython.lib and object 
Release/vtkFilteringPython.exp
vtkCellLocatorPython.obj : error LNK2001: unresolved external symbol 
_PyVTKClass_vtkLocatorNew
vtkColorTransferFunctionPython.obj : error LNK2001: unresolved external 
symbol _PyVTKClass_vtkScalarsToColorsNew
[...]
Release/vtkFilteringPython.dll : fatal error LNK1120: 10 unresolved externals
Error executing link.exe.

ALL_BUILD - 28 error(s), 0 warning(s)
******************************

The Common lib is parsed correctly. The error is triggered while linking 
the Filtering lib, which depends on Common. The 28 errors match exactly the 
signatures of functions belonging to *abstract* classes stored in Common. 
It appears that, although wrapped and compiled, the Common abstract classes 
are not linked and stored in vtkCommonPython.lib (or dll). Thus, linking 
Filtering fails. This is problematic. I was unable to find a solution.

Hope this helps.





More information about the vtk-developers mailing list