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

Ken Martin ken.martin at kitware.com
Tue May 8 09:25:14 EDT 2001


Hello Sebastien,
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).

Feel free to commit the fixes. (for example the LIBRARY_SRCS versus
Common_SRCS fix)

 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 plan is that once CMake settles down, it will be provided as a binary
distribution for most platforms. The source will of course also be
available. I do not think we will put the CMake binaries (or source) in the
VTK tree. It will be a separate tool, sort of like gmake.


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 ?

Release min size produces much smaller libraries that may not execute as
quickly. For example on Release MinSize no inlines are done.

"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.

If BUILD_SHARED_LIBS is not set, then you built static libraries.

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 seems that MSVC keeps some sort of option file that remembers your last
target and switching between Static and DLL causes those warnings. You must
rebuild everything when switching because the object files are different
between Static and DLL (I believe the subdirectories are actually Debug,
Release, ReleaseMinSize, DebugDLL, ReleaseDLL

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.

This is an open issue. I haven't thought about how to do this yet. Maybe
have a target that copies the DLLs to a common directory.

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).


That is also an open issue.

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).

I believe that is correct

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 :

That is correct.


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 :(

That is a problem

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.

The python libraries should be variables, determined in a FindPython.cmake
module and then used in the subdirectories. Just haven't gotten around to
that for a few reasons.

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.


I believe this is because the old vtkpython was one DLL and in the new build
right now it is multiple DLLs, which means that the FooNew functions now
need a VTK_EXPORT in their signature, which means a small mod to
vtkWrapPython which I hasn't been done yet.

Thanks for the feedback and feel free to take a stab at fixing up stuff.

Ken





More information about the vtk-developers mailing list