Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

A Practical Guide to Compiling C based Modules under ActiveState using Microsoft C++

by tachyon (Chancellor)
on Apr 11, 2003 at 04:43 UTC ( [id://249803]=perltutorial: print w/replies, xml ) Need Help??

If you are like me and work mainly on Win32 and use ActiveState Perl you have probably been frustrated more than once when you could not get a ppd (with a compiled binary of Some::CModule). You probably tried running nmake and got a bunch of errors. Maybe you got cygwin or MinGW so you could get your hands on gcc. Then you were frustrated because it still won't work.....

If so then this tutorial is for you. It shows you how to get Perl modules with C code compiling under ActiveState using Microsoft C++

Get a copy of Microsoft Visual C++ .NET. You can get all the bits you need from Microsoft for free as described at Free MSVC tools + Activestate to compile CPAN Modules. The reason you need this is that ActiveState uses it to build Perl and if you want to build Perl C modules for ActiveState Perl you have to emulate their build environment. An alternative is to compile Perl from scratch yourself using cygwin/MinGW and gcc. But if you do that you will lose ppm functionality and you don't need this guide.

You actually only need a few bits which are detailed below.

Directory of C:\cl 05/01/2002 10:33a 917,504 c1.dll 05/01/2002 09:48a 774,144 c2.dll 05/01/2002 09:48a 81,920 cl.exe 05/01/2002 07:54a 262 cl.exe.config 26/03/2004 10:17a <DIR> include 26/03/2004 10:18a <DIR> lib 05/01/2002 09:49a 643,072 link.exe 05/01/2002 07:54a 262 link.exe.config 05/01/2002 09:25a 73,728 msobj10.dll 05/01/2002 09:22a 233,472 mspdb70.dll 05/01/2002 10:37a 344,064 msvcr70.dll 16/09/1994 06:00a 5,056 nmake.err 16/09/1994 06:00a 65,536 nmake.exe 11 File(s) 3,151,004 bytes 5 Dir(s) 938,143,744 bytes free

You basically need cl.exe which is the MS C/C++ compiler, link.exe which is the linker, and nmake.exe (M$ version of make) and their associated DLLs. You also need a whole bunch of header .h files and library .lib files. As you can see from above you can just package these up out of the VCC distro (it zips to just under 20MB) and beats a 2GB install just to get a compiler. But I digress.

I assume you already have nmake installed but it comes with the M$ C++ distro or is available for free online. See A Guide to Installing Modules for details.

I'll Assume you already have a copy of ActiveState Perl 5.6. Set aside about 2 hours to install the 2000MB of Visual Studio C++ .NET! (Now you see why it is worth packaging just the raw tools?). If you are downloading the free tools you will be downloading about 200MB, but the install is shorter. Once this is done you need follow these steps.

First add these to your path so that cl.exe (the MS command line C/C++ compiler) will actually work work of the command line. By default it won't because the install forgets to set the required paths! There is a utility called vcvars32.bat in the same dir as CL.EXE that calls vsvars.bat in the Microsoft Visual Studio .NET\Common7\Tools dir that will set these for you automatically as noted by PodMaster. Don't bother looking for the docs on this, cause they ain't there AFAIK. You are just expected to divine this fact. Favorite M$ comment goes here.

Right click My Computer|Properties|Advanced|Environment Variables. Now edit the path statement and add (assuming you did a default location install):

C:\Program Files\Microsoft Visual Studio .NET\Vc7\bin; C;\Program Files\Common Files\Microsoft Shared\VSA\7.0\VsaEnv;

You also need to add the LIB and INCLUDE environment variables.

INCLUDE C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\inc +lude\ LIB C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Lib\

PodMaster knows far more than me and points out that there is a little batch script called VSVARS32.BAT that lives in C:\Program Files\Microsoft Visual Studio .NET\Common7\Tools\vsvars32.bat with VC7. Run that and it will set up your environment vars for you (path + env vars)

OK away to get out of My Computer. Get a command prompt. Start|Run|cmd and try out the cl command. You should get the usage message. If not check your paths and try again. Note you need to close the cmd window as it will not take the new path until it is reopened.

Now you may or may not need to do the following. By rights you probably should not, however we are trying to emulate the exact build environment used at Active State and I have on at least one occasion found this step fixed a compilation error. Copy all files from these locations into Perl\lib\CORE

C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\*.* C:\Program Files\Microsoft Visual Studio .NET\Vc7\PlatformSDK\Include\ +*.* C:\Program Files\Microsoft Visual Studio .NET\Vc7\lib\*.* C:\Program Files\Microsoft Visual Studio .NET\Vc7\PlatformSDK\lib\*.*

There will be some overwrite prompts. No to all is probably a safe bet. Now just:

$ perl Makefile.PL $ nmake $ nmake test $ nmake install

And you should be able to build the majority of C based modules on Win32. Note that you will not be able to build them all because some are system specific and as a result just don't run on Win32. You will also get compiler issues related to the fact that most of them will have been tested using gcc and C compilers a notorious for being picky about their code. Anyway a lot will JUST WORK. If you are feeling generous read up on PPM and package them in a repository for everyone to use like some monks do.

cheers

tachyon

Replies are listed 'Best First'.
Re: A Practical Guide to Compiling C based Modules under ActiveState using Microsoft C++
by PodMaster (Abbot) on Apr 11, 2003 at 06:13 UTC
    If you wish to avoid modifying the registry, simply run vcvars32.bat which will set up the appropriate environment variables (modify PATH, add LIB and INCLUDE) before attempting to nmake. vcvars32.bat is specific to MSVS6, but i'm sure MSVS .NET has a similary named batch file which will setup the environment. It's located right next to CL.exe.

    I'd really like to stress the importance of reading the README/INSTALL that come with modules. They'll often have common problems( and usually their solutions) others have had trying to compile said extension on win32.

    I'd also like to add that you should not be afraid of editing Makefile.PL. Get familiar with ExtUtils::MakeMaker. Most of the time you can get away with modifying your INCLUDE/LIBS environment variables, but not all Makefile.PL's are created equal, and some are written quite poorly (in a non-portable fashion, for no apparent reason -- for example, WriteMakefile is passed 'OBJECT' => '$(O_FILES) '." Foo.o Bar.o Baz.o " which won't fly on windows. The right way to write it would've been as "Foo$Config{obj_ext} Bar$Config{obj_ext} Baz$Config{obj_ext}").

    Another common portability issue is #include <uninstd.h>. Lots of extensions include it, but windows has no such beast, and it belongs in an #ifndef. Simply comment it out, and there'll be a good chance the extension will compile.

    Also, if a required library will not build on windows, all hope is not lost. You can always get MinGW (aka cygwin), compile the required library, and link with it.

    Read How can an MSVC program call a MinGW DLL, and vice versa? on how to do it.

    I recently did that with Math::GMP (it's up on my repository), cause it's a requirement for Net::SSH::Perl. If you can live with running GMP via cygwin, you can have Math::GMP on windows.

    It is also important to make sure when compiling libraries required for a module to work, like in the case of pure-db, that your compiler options match those of your perl binary. CL /? will reveal the following possible options

    -LINKING- /MD link with MSVCRT.LIB /MDd link with MSVCRTD.LIB de +bug lib /ML link with LIBC.LIB /MLd link with LIBCD.LIB debu +g lib /MT link with LIBCMT.LIB /MTd link with LIBCMTD.LIB de +bug lib /LD Create .DLL /F<num> set stack size /LDd Create .DLL debug libary /link [linker options and lib +raries]
    What you want is what your perl has
    perl -V:ccflags ccflags='-nologo -O1 -MD -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT -DHAV +E_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DPERL_MSVC +RT_READFIX';
    So you'd wanna make sure the -MD option is present. A tell-tale sign that the library you're trying to link to was not compiled with the -MD option is an "unresolved external symbol _pctype".

    If you're faced with an error, google it, check rt.cpan.org, check testers.cpan.org (the mailing list archives as well) because chances are, somebody has already encountered it and there is a workaround available, and if there isn't, simply report it to the author, cause he'll usually be able to help you.

    update: If you get unresolved external symbol _snprintf, you'll need (this is not like the _pctype issue):

    #ifdef WIN32 #define snprintf _snprintf #endif


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      Hi, I'm building a Perl extension (dll in Windows XP) using ExtUtils::MakeMaker. This dll needs to link with other libraries that were built in static mode (-MTd). My perl configuration states dynamic libraries (-MD) which causes MakeMaker to pull a dynamic C library (msvcrtd.dll). The other libraries are using the static C library (libcmtd.lib) These dynamic and static C libraries collide giving link errors. Is there a way to force perl to compile with (-MTd) albeit its configuration flags? Thanks, Avner Moshkovitz Research Analyst MacDonald Dettwiler Direct: (604) 231-2487 13800 Commerce Parkway Fax: (604) 278-2117 Richmond, B.C. Canada V6V 2J3 Email: amoshkov@mda.ca www: www.mda.ca
Re: A Practical Guide to Compiling C based Modules under ActiveState using Microsoft C++
by Corion (Patriarch) on Apr 11, 2003 at 06:26 UTC

    Obviously, it also helps to know a bit of C to successfully install modules that fail make. I don't know much C, but the stuff that will most likely bite you when installing/compiling C extensions are platform / header file differences.

    My approach to hacking at a C extension is, that the C code in principle works and that the included Perl tests exercise the extension behaviour good enough to uncover most things I break when dabbling.

    Things that I did to get stuff to compile :

    • #define long int - in HTML::Tidy, I had to make VC6 believe through the preprocessor that an int and a long were the same thing (which, on a 32bit machine, they are) to get it to compile. The error message said something like need explicit cast from int to long, but I didn't want to modify anything in the actual C code.
    • Replaced a #define define INTPTR_TYPE long long by # define INTPTR_TYPE __int64 . This was prompted by the VC error error C2632: 'long' followed by 'long' is illegal, as long long is a gcc extension AFAIK.

    So don't be afraid to change bits in the C header files to adjust the C code to what you think your machine actually is, but do pass these changes upstream to the module author - the next release might have your change already built in - and also be prepared for bugs in your modified versions - keep track of what you changed and which extensions you compiled yourself.

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
      I thought I would add a caveat to this thread so others can find it.

      I use the Perl API on Windows with Visual Studio C++. While moving from Perl 5.8 to 5.20 the Perl API headers generated compile time errors.

      The first error was:

      c:\perl.5.20\lib\core\op_reg_common.h(58) : error C2144: syntax error +: 'void' should be preceded by ';'

      SE keywords: op_reg_common.h void preceded

      Someone in the IRC irc.perl.org #xs chat channel referenced here. http://sourceforge.net/p/staf/support-requests/180/

      Basically I needed to edit the config.h file from

      #define PERL_STATIC_INLINE static __inline__ /**/
      to
      #define PERL_STATIC_INLINE static __inline /**/
      I don't know why it wasn't defined with ifdefs for each compiler.

      J.R. Heisey

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perltutorial [id://249803]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-03-19 06:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found