Problem with Makefile for MS VC++: Cannot open include file:

Dear ROOTers

As a test to convert my program for WinXP I have created a test program “myclassR1” (see attachement).
For this I have created “Makefile.win32” (see attached file) which I have adapted from root/test.
Using this Makefile.win32, I can compile myclassR1 as DLL using MS VC++ 2008.

The problem is that I need to create the DLL as part of my package for “R”, which by default compiles
C/C++ code using MinGW. However, VC++ can also be used to “compile the objects and
build the DLL” in the following way:

	cl /MT /Ox /D "WIN32"  /c *.c
	link /dll /def:mypkg.def /out:mypkg.dll *.obj Rdll.lib

where I need to create the .def file by hand (which I did).

When testing to create an R package with a program containing C++ classes w/o ROOT I could indeed
create the necessary Makfile.win. However, trying to create the “Makefile.win” for “myclassR1”
(see the attached Makefile.win), I get the following output:

Microsoft (R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

        cl /Ic:\root/include /MT /EHsc /Ox /D "MSVC" /D "WIN32" /c MyClassC.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassC.cxx
Generating dictionary MyClassCDict.cxx...
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassCDict.cxx
        cl /Ic:\root/include /MT /EHsc /Ox /D "MSVC" /D "WIN32" /c MyClassA.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassA.cxx
        cl /Ic:\root/include /MT /EHsc /Ox /D "MSVC" /D "WIN32" /c MyClassB.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassB.cxx
        cl /Ic:\root/include /MT /EHsc /Ox /D "MSVC" /D "WIN32" /c rwrapper.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

rwrapper.cxx
        cl  /c MyClassCDict.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassCDict.cxx
MyClassCDict.cxx(7) : fatal error C1083: Cannot open include file: 'RConfig.h': No such fi
le or directory
NMAKE : fatal error U1077: '"C:\Programme\Microsoft Visual Studio 9.0\VC\BIN\cl.EXE"' : re
turn code '0x2'
Stop.

The problem seems to be when trying to linke the code?
Can someone please tell me what is missing in my Makefile.win?

I would greatly appreciate any help from the Windows experts.

Thank you in advance.
Best regards
Christian
Makefile.win32.txt (3.71 KB)
Makefile.win.txt (3 KB)
myclassR1.tar.gz (8.83 KB)

Hi Christian,

Apparently the path to ROOT include directory is missing. Try to add:
-I$(ROOTSYS)/include
in the compilation flags.
And I would advise to not use -MT flag, but -MD or -MDd (using dll runtime libraries, and not static ones). It may conflict with the ones used by ROOT dlls.
If it still doesn’t work, please let me know, and I will take a look at your files later today.

Cheers, Bertrand.

Dear Bertrand

Thank you for your comments to which I would like to respond:

1, When you look at “Makefile.win” you will see that I did include “/I$(ROOTSYS)/include”
Sadly, this did not help. It allowed compiling the different classes but failed when linking.
Do you have any ideas?

2, MT vs MD:
I am attaching an even simpler example “MyClass” which contains C++ classes but does not depend on ROOT.
When I compile this source code for R using “Makefile.win” containing “/MT”, I can install the
corresponding package into “R”. However, simply changing “/MT” to “/MD” causes the following error:

C:\home\Rabbitus\CRAN>R CMD check MyClass_0.4.1.tar.gz
* checking whether the package can be loaded ... ERROR
Error in dyn.load(file, ...) : 
  cannot load shared library 'C:/home/Rabbitus/CRAN/MyClass.Rcheck/MyClass/libs/MyClass.dll':
 LoadLibrary failure:  A DLL-Initialisation routine failed.

and the following dialogbox:
Microsoft Visual C++ Runtime Library
Runtime Error!
Program:c:\Programme\R\R-2.6.2\bin\Rterm.exe
R6034
An application has made an attempt to load the C runtime library incorrectly.
Please contact the application’s support team for more information.

As you see it is not possible to use “/MD”.

Furthermore, when trying to use “Makefile.win32” instead of “Makefile.win” I get the following error:

C:\home\Rabbitus\CRAN>R CMD check MyClass_0.4.1.tar.gz
  running src/Makefile.win32 ...
Makefile.win32: *** missing separator.  Stop.
make[2]: *** [srcDynlib] Error 2
make[1]: *** [all] Error 2
make: *** [pkg-MyClass] Error 2

I do not understand this error, since when running "NMAKE /f “Makefile.win32” CFG=“Release”
everything is ok.

Best regards
Christian
MyClass.tar.gz (4.24 KB)

Hi Christian,

OK, I will take a look when I’ll switch back to Windows (or tomorrow)

Cheers, Bertrand.

Dear Bertrand

Finally, I was able to create a “Makefile.win” which allows to compile my example “myclassR1”.
Thus, I am attaching “myclassR1.tar.gz” containing two different makefiles, “Makefile.win” and
“Makefile.win32” which both work, and an example macro.

However, compiling this source code for R using “Makefile.win” now results in the following error:

C:\home\Rabbitus\CRAN>R CMD check myclassR1_0.3.2.tar.gz
  running src/Makefile.win ...
cl /Ic:\root/include /MT /EHsc /Ox /D "MSVC" /D "WIN32" /c MyClassC.cxx
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MyClassC.cxx
MyClassC.cxx(1) : fatal error C1083: Cannot open include file: 'Riostream.h': No such file or directory
make[3]: *** [MyClassC.obj] Error 2
make[2]: *** [srcDynlib] Error 2
make[1]: *** [all] Error 2
make: *** [pkg-myclassR1] Error 2

I know that this seems now to be an R-related problem, but maybe you could give me a hint, how
to change “Makefile.win”, so that calling it from a foreign environment will find “root/include”?

Best regards
Christian
myclassR1.tar.gz (8.87 KB)

Dear Bertrand

Now I could solve the last problem:
In the “Makefile.win” I forgot to define "ROOTSYS = C:\root"
With this information R is able to find the include files.

Best regards
Christian

Hi Christian,

OK, good. Then everything is fixed now?

Cheers,
Bertrand.

Dear Bertrand

Yes, for the moment, since now I have to create a Makefile for my real program,
which is quite complex. It is good to know that I can ask you, when I have a problem.

Best regards
Christian

Dear Bertrand

Now that I could solve all problems with my makefile (thanks to your help), there is one remaining problem:
As I have mentioned last time, I forgot to define “ROOTSYS = C:\root” in “Makefile.win”. However, hardcoding
ROOTSYS is not a solution, so my last problem is to create a “configure.win” file.

The “configure.win” file needs to do the following:

  1. check if ROOT is installed in a fixed location
  2. define ROOTSYS
  3. check if ROOT PATH variables are defined
  4. check if and where VC++ is installed, and which version XX of VC++
  5. call “C:\Program Files\Microsoft Visual Studio XX\VC\vcvarsall.bat” (Is this necessary?)

I am attaching the “configure.in” file which I created for Linux and MacOSX.

My question is how do I create the corresponding “configure.win” file for VC++?

Note: Since the installation of “R” requires installation of MinGW and a subset of cygwin tools,
the “configure.win” file is probably read by cygwin tools.

Best regards
Christian
configure.in.txt (2.74 KB)

Hi Christian,

Please take a look at the attached script (working in a cygwin shell). It detects location of Visual C++ install dir, and sets a few environment variables… You will probably have to adapt it to your needs…
Hope it will help :wink:

Cheers, Bertrand.
test_script.sh.txt (1.35 KB)

Dear Bertrand

Thank you very much for your test script.
I am just testing it, but have some problems.

Here is the “makefile.win” script:

# check if ROOT is installed in fixed location:
echo "testing ROOT..."
if test "${ROOTSYS}"; then
   echo "found ROOT version `root-config --version` in directory `root-config --prefix`"
fi

echo ""
echo "PATH = $PATH"
echo ""
echo "INCLUDE = $INCLUDE"
echo ""
echo "LIB = $LIB"
echo ""

# check if MSVC++ is installed:
echo "testing MSVC++..."
MSTMPDIR="`which cl.exe|sed 's,/BIN/cl\.exe$,,'`"
MSVCDIR=`cygpath -w "${MSTMPDIR}"`
VCINSTALLDIR=`cygpath -w ${MSTMPDIR} |sed 's,\\\\VC\?.$,,'`
if test "${MSVCDIR}"; then
   echo "found MSVC++ in directory "${VCINSTALLDIR}""

fi

Here is the output that I get:

---------- Making package xps ------------
testing ROOT...
./configure.win: root-config: not found
./configure.win: root-config: not found
found ROOT version  in directory

PATH = /cygdrive/c/Programme/R/R-2.6.2/bin:/cygdrive/c/Rtools/bin:/cygdrive/c/Rtools/perl/
bin:/cygdrive/c/Rtools/MinGW/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdriv
e/c/WINDOWS/System32/Wbem:/cygdrive/c/Programme/Microsoft SQL Server/90/Tools/binn/:PATH=C
:/Rtools/bin:/cygdrive/c/Rtools/perl/bin:/cygdrive/c/Rtools/MinGW/bin:/cygdrive/c/Programm
e/HTML Help Workshop:/cygdrive/c/Programme/R/R-2.6.2/bin:/cygdrive/c/root/bin:/cygdrive/c/
Programme/Microsoft Visual Studio 9.0/VC/bin:/cygdrive/c/Programme/Microsoft SDKs/Windows/
v6.0A/bin:/cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/redist/x86/Microsoft.VC90.C
RT

INCLUDE = C:\Programme\Microsoft Visual Studio 9.0\VC\include;C:\Programme\Microsoft SDKs\
Windows\v6.0A\Include

LIB = C:\Programme\Microsoft Visual Studio 9.0\VC\lib;C:\Programme\Microsoft SDKs\Windows\
v6.0A\Lib;C:\root\lib

testing MSVC++...
which: not found
cygpath: not found
cygpath: not found
make[2]: *** [C:/home/Rabbitus/CRAN/myRlib/xps/zzzz] Error 1
make[1]: *** [all] Error 2
make: *** [pkg-xps] Error 2
*** Installation of xps failed ***

As you see, root-config is not found (although it is located in root/bin).
What is the reason for this?

Furthermore, “which” is not found since this not included in the cygwin subset used by R.
Do you know a workaround solution? (“sed” is included)

Finally, “cygpath” is also not found, since it is not defined.
Do you know a substitution (based on my PATH output)?

Thank you
Christian

Hi Christian,

[quote]As you see, root-config is not found (although it is located in root/bin).
What is the reason for this?[/quote]
No idea…

[quote]Furthermore, “which” is not found since this not included in the cygwin subset used by R.
Do you know a workaround solution? (“sed” is included)

Finally, “cygpath” is also not found, since it is not defined.
Do you know a substitution (based on my PATH output)?[/quote]
Please try the two scripts in attachment.

Cheers,
Bertrand.
which.txt (165 Bytes)
cygpath.txt (713 Bytes)

Dear Bertrand

Thank you very much for your scripts, however, for some reason they are not recognized.

Here is the modified “makefile.win” script to demonstrate the behavior:

# check if ROOT is installed in fixed location:
echo "testing ROOT..."
if test "${ROOTSYS}"; then
   PWD=`pwd`
   echo "PWD = $PWD"
   cd ${ROOTSYS}/bin
   NEWPWD=`pwd`
   echo "NEWPWD = $NEWPWD"
   echo "found ROOT version `root-config --version` in directory `root-config --prefix`"
   cd ${PWD}
   echo "PWD = $PWD"
fi

echo ""
echo "PATH = $PATH"
echo ""

PWD=`pwd`
echo "PWD = $PWD"
echo ""

TESTDIR=`perl 'test.pl'`
echo "TESTDIR = $TESTDIR"
echo ""

# check if MSVC++ is installed:
echo "testing MSVC++..."
MSTMPDIR="`which cl.exe|sed 's,/BIN/cl\.exe$,,'`"
echo "1, MSTMPDIR = $MSTMPDIR"
MSTMPDIR="`type -p cl.exe|sed 's,/BIN/cl\.exe$,,'`"
echo "2, MSTMPDIR = $MSTMPDIR"
MSTMPDIR="`type cl.exe|sed 's,/BIN/cl\.exe$,,'`"
#MSTMPDIR="`type cl.exe`"
echo "3, MSTMPDIR = $MSTMPDIR"
MSVCDIR=`cygpath -w "${MSTMPDIR}"`
echo "MSVCDIR = $MSVCDIR"
VCINSTALLDIR=`cygpath -w ${MSTMPDIR} |sed 's,\\\\VC\?.$,,'`
echo "VCINSTALLDIR = $VCINSTALLDIR"
if test "${MSVCDIR}"; then
   echo "found MSVC++ in directory "${VCINSTALLDIR}""

fi

Here is the output that I get:

---------- Making package xps ------------
testing ROOT...
PWD = /cygdrive/c/home/Rabbitus/CRAN/R.INSTALL.2056/xps
NEWPWD = /cygdrive/c/root/bin
./configure.win: root-config: not found
./configure.win: root-config: not found
found ROOT version  in directory
PWD = /cygdrive/c/home/Rabbitus/CRAN/R.INSTALL.2056/xps

PATH = /cygdrive/c/Programme/R/R-2.6.2/bin:/cygdrive/c/Programme/Microsoft Visual Studio 9
.0/Common7/IDE:/cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/BIN:/cygdrive/c/Progra
mme/Microsoft Visual Studio 9.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/
v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Programme/Microsof
t Visual Studio 9.0/VC/VCPackages:/cygdrive/c/Programme/Microsoft SDKs/Windows/v6.0A/bin:/
cygdrive/c/Rtools/bin:/cygdrive/c/Rtools/perl/bin:/cygdrive/c/Rtools/MinGW/bin:/cygdrive/c
/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Progra
mme/Microsoft SQL Server/90/Tools/binn/:PATH=C:/Rtools/bin:/cygdrive/c/Rtools/perl/bin:/cy
gdrive/c/Rtools/MinGW/bin:/cygdrive/c/Programme/HTML Help Workshop:/cygdrive/c/Programme/R
/R-2.6.2/bin:/cygdrive/c/root/bin:/cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/bin
:/cygdrive/c/Programme/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/Programme/Microsoft Vi
sual Studio 9.0/VC/redist/x86/Microsoft.VC90.CRT

PWD = /cygdrive/c/home/Rabbitus/CRAN/R.INSTALL.2056/xps

TESTDIR = c:\Programme\Microsoft Visual Studio 9.0\VC\BIN

testing MSVC++...
which: not found
1, MSTMPDIR =
2, MSTMPDIR = -p not found
cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC
3, MSTMPDIR = cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC
cygpath: not found
MSVCDIR =
cygpath: not found
VCINSTALLDIR =
make[2]: *** [C:/home/Rabbitus/CRAN/myRlib/xps/zzzz] Error 1

The results show the following:

1, root-config:
Although I changed the directory to root/bin, “root-config” is still not recognized.

2, which:

  • Although I placed the file “which” in the same directory as “config.win”, it is not recognized.
  • When I replace “which” with “type -p” the option “-p” is not recognized.
  • Only “type cl.exe” prints the result, but with "cl.exe is …"
    Thus it seems that “type” is not the unix shell command but the DOS shell command.

3, PERL:
Since R uses multiple perl scripts, it seems that only perl scripts are recognized.
Thus I have tested “perl ‘test.pl’” to get $TESTDIR with the following code for “test.pl”:

use strict;
use Cwd;

my @path = split(';', $ENV{PATH});
s/"//g for @path;
@path = grep length, @path;
print "@path[2]";

I have modified the code from package File::Spec::Win32 for “sub path” and hardcoded “path[2]”,
since I have always problems using grep.

It would be great if you could help me to modify the perl script to get $MSVCDIR and $VCINSTALLDIR.

Thank you in advance.
Best regards
Christian

Hi Christian,

Try to put the scripts in C:/Rtools/MinGW/bin and make them executable (chmod +x which cygpath)
FYI, I will be away until wednesday 26th, so I will take a look when back if you don’t manage to investigate yourself…

Cheers, Bertrand.

Dear Bertrand

First, thank you for your continuous help, and “Happy Easter Holiday”!

I tried your suggestion, but it does not work since “chmod” is also not known.
In Rtools and MinGW all programs are executables, e.g. sh.exe, and on the commandline it is possible to use both shell scripts:

C:\home\Rabbitus\CRAN\xps>sh which cl.exe
-p not found
cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/bin/cl.exe

C:\home\Rabbitus\CRAN\xps>sh cygpath -w  "/cygdrive/c/Programme/Microsoft Visual Studio 9.
0/VC/bin/cl.exe"
\cygdrive\c\Programme\Microsoft Visual Studio 9.0\VC\bin\cl.exe

As you see “which” is using the DOS command “type” since “type.exe” does not exist either, but “cygpath” is working.

Just now I realized that in “config.win” writing “sh which” and “sh cygpath” would solve the problem if “which” could use the unix version of “type” and not the DOS command, since I get:

testing MSVC++...
1, MSTMPDIR = -p not found
cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/bin/cl.exe
2, MSTMPDIR = -p not found
cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/bin/cl.exe
3, MSTMPDIR = cl.exe is /cygdrive/c/Programme/Microsoft Visual Studio 9.0/VC/bin/cl.exe
MSVCDIR = cl.exe is \cygdrive\c\Programme\Microsoft Visual Studio 9.0\VC\bin\cl.exe
VCINSTALLDIR = cl.exe
found MSVC++ in directory cl.exe

I will try to find a solution, otherwise I would need to use a perl script.

Best regards and happy holidays.
Christian

Dear Christian,

[quote]First, thank you for your continuous help[/quote]You’re most welcome :slight_smile:

[quote]“Happy Easter Holiday”![/quote]Thanks! :slight_smile: Likewise!

Cheers, Bertrand.

Dear Bertrand

Thank you for this link, but I cannot use it:
I am writing the config.win file only to check if other users have installed ROOT and VC++.
I cannot assume that other R users will download and install the Windows version of “which”.
I have to live with the fact that they have installed the recommended Rtools from:
murdoch-sutherland.com/Rtools/
and nothing else.

Best regards
Christian

Dear Bertrand

Thank you once again for your help.

For the records I present the solution that I found, which uses perl scripts as I have mentioned.

Here is the config.win file which checks for the presence of ROOT and VC++:

# check if ROOT is installed in fixed location:
echo "testing for presence of ROOT..."

ROOTEXE=`perl 'findroot.pl'`
if [ "${ROOTEXE}" = "ERR_ROOTSYS" ]; then
   echo "   The environment variable ROOTSYS was not found."
   echo "   Please set ROOTSYS to the directory where ROOT is located."
   exit 1
elif [ "${ROOTEXE}" = "ERR_ROOTEXE" ]; then
   echo "   The ROOT binary root.exe was not found in directory ${ROOTSYS}/bin."
   echo "   Please install ROOT for Windows and/or check ROOTSYS."
   exit 1
else
   echo "   found ${ROOTEXE} of ROOT in directory ${ROOTSYS}/bin...OK"
#   echo "   found ROOT version `root-config --version` in directory `root-config --prefix`"
fi

# check if MSVC++ is installed:
echo "testing for presence of MSVC++..."
VCCLEXE=`perl 'findvc.pl'`
if [ "${VCCLEXE}" = "ERR_CLEXE" ]; then
   echo "   The VC++ compiler cl.exe was not found."
   echo "   Please install Microsoft Visual C++ or check the settings."
   exit 1
else
   echo "   found ${VCCLEXE} of Visual C++...OK"
fi

exit 0

The first perl script is findroot.pl:

use strict;
use File::Find;

# check if ROOTSYS exists
my $rootsys = $ENV{ROOTSYS};
if (!($rootsys =~ /root$/)) {
   print("ERR_ROOTSYS");
   exit;
}#if

# input file names
my $file2find   = "root.exe";
my @directories = ($rootsys);

# output file names
my $file_found;
my $dir_found;

# check if root is installed in fixed location
find(\&wanted, @directories);

sub wanted {
   if ($_ =~ /$file2find$/) { #need to avoid finding "../man1/root.exe.1"
      $file_found = $_;
      $dir_found  = $File::Find::dir;
      last;
   }#if
}#sub

# return result
if ($file_found =~ /^root.exe$/) {
   print ("$file_found");
} else {
   print("ERR_ROOTEXE");
}#if

The second perl script is findvc.pl:

use strict;
use File::Find;

# get path containing "..\VC\BIN"
my @path = split(';', $ENV{PATH});
my $pathvc = "";
my $i;
for $i (0..$#path) {
   if ($path[$i] =~ /VC\\BIN$/) {
      $pathvc = $path[$i];
      last;
   }#if
}#for

# input file names
my $file2find   = "cl.exe";
my @directories = ($pathvc);

# output file names
my $file_found = "";
my $dir_found  = "";

# check if VC++ is installed in fixed location
find(\&wanted, @directories);

sub wanted {
   if ($_ =~ /$file2find$/) {
      $file_found = $_;
      $dir_found  = $File::Find::dir;
      last;
   }#if
}#sub

# return result
if ($file_found =~ /^cl.exe$/) {
   print ("$file_found");
} else {
   print("ERR_CLEXE");
}#if

There may be simpler solutions, but I am not a perl expert and for my purposes it works fine.

Best regards
Christian

Hi Christian,

Good to see you found a working solution :slight_smile:

Cheers, Bertrand.