Index: README ================================================================== --- README +++ README @@ -48,25 +48,22 @@ WINDOWS BUILD ============= See the tcl/win/README file included in the Tcl src dist for details -about how to build the extension under Windows. We suggest using -the Msys + Mingw build process since it is significantly easier -than building with VC++ or Cygwin. - -This package includes a Visual Studio project file to help in building -with VC++. - -The package has been built using both VC++6 and Msys + Mingw. - -Microsoft Platform SDK 2003 is required for building. The following minimal -example will install the extension in the C:\Tcl\lib directory. +about how to build the extension under Windows. + +The following minimal example will build and install the extension in the +C:\Tcl\lib directory. $ cd tcludp/win $ nmake -f makefile.vc realclean all - $ nmake -f makefile.vc install INSTALLDIR=C:\Tcl\lib + $ nmake -f makefile.vc install INSTALLDIR=C:\Tcl + +The Visual Studio project file included in the win directory +is *ancient* and deprecated. It is not suitable for modern versions +of Tcl and Visual Studio. DOCUMENTATION BUILD =================== Use the following command to create the UNIX documentation (based on udp.man file): Index: generic/udp_tcl.c ================================================================== --- generic/udp_tcl.c +++ generic/udp_tcl.c @@ -263,11 +263,15 @@ */ int udpOpen(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char * argv[]) { +#ifdef WIN32 + SOCKET sock; +#else int sock; +#endif char channelName[20]; UdpState *statePtr; uint16_t localport = 0; int reuse = 0; struct sockaddr_storage addr,sockaddr; @@ -372,11 +376,11 @@ sock, ntohs(localport)); statePtr = (UdpState *) ckalloc((unsigned) sizeof(UdpState)); memset(statePtr, 0, sizeof(UdpState)); statePtr->sock = sock; - sprintf(channelName, "sock%d", statePtr->sock); + sprintf(channelName, "sock" SOCKET_PRINTF_FMT, statePtr->sock); statePtr->channel = Tcl_CreateChannel(&Udp_ChannelType, channelName, (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE | TCL_MODE_NONBLOCKING)); statePtr->doread = 1; statePtr->multicast = 0; @@ -637,11 +641,11 @@ /* * In windows, do not use getnameinfo() since this function does * not work correctly in case of multithreaded. Also inet_ntop() is * not available in older windows versions. */ - if (WSAAddressToString((struct sockaddr *)&recvaddr,socksize, + if (WSAAddressToStringA((struct sockaddr *)&recvaddr,socksize, NULL,remoteaddr,&remoteaddrlen)==0) { /* * We now have an address in the format of : * Search backwards for the last ':' */ @@ -806,33 +810,14 @@ static int hasSockets = 0; /* 1 if the system supports sockets. */ HANDLE socketThread; DWORD id; if (!initialized) { - OSVERSIONINFO info; - initialized = 1; - /* - * Find out if we're running on Win32s. - */ - - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&info); - - /* - * Check to see if Sockets are supported on this system. Since - * win32s panics if we call WSAStartup on a system that doesn't - * have winsock.dll, we need to look for it on the system first. - * If we find winsock, then load the library and initialize the - * stub table. - */ - - if ((info.dwPlatformId != VER_PLATFORM_WIN32s) - || (SearchPath(NULL, "WINSOCK", ".DLL", 0, NULL, NULL) != 0)) { - hasSockets = InitSockets(); - } + /* Load the library and initialize the stub table. */ + hasSockets = InitSockets(); /* * Start the socketThread window and set the thread priority of the * socketThread as highest */ @@ -878,11 +863,15 @@ * ---------------------------------------------------------------------- */ static int udpClose(ClientData instanceData, Tcl_Interp *interp) { +#ifdef _WIN32 + SOCKET sock; +#else int sock; +#endif int errorCode = 0; int objc; Tcl_Obj **objv; UdpState *statePtr = (UdpState *) instanceData; #ifdef WIN32 @@ -939,11 +928,11 @@ ckfree((char *) statePtr); if (errorCode != 0) { #ifndef WIN32 sprintf(errBuf, "udp_close: %d, error: %d\n", sock, errorCode); #else - sprintf(errBuf, "udp_cose: %d, error: %d\n", sock, WSAGetLastError()); + sprintf(errBuf, "udp_close: " SOCKET_PRINTF_FMT ", error: %d\n", sock, WSAGetLastError()); #endif UDPTRACE("UDP error - close %d", sock); } else { UDPTRACE("Close socket %d\n", sock); } @@ -1930,11 +1919,11 @@ #ifdef WIN32 static char buffer[1024]; va_start (args, format); _vsnprintf(buffer, 1023, format, args); - OutputDebugString(buffer); + OutputDebugStringA(buffer); #else /* ! WIN32 */ va_start (args, format); vfprintf(dbg, format, args); Index: generic/udp_tcl.h ================================================================== --- generic/udp_tcl.h +++ generic/udp_tcl.h @@ -85,11 +85,15 @@ #endif /* WIN32 */ typedef struct UdpState { Tcl_Channel channel; +#ifdef _WIN32 + SOCKET sock; +#else int sock; +#endif char remotehost[256]; /* send packets to */ uint16_t remoteport; char peerhost[256]; /* receive packets from */ uint16_t peerport; uint16_t localport; @@ -105,10 +109,17 @@ short ss_family; /* indicator set for ipv4 or ipv6 usage */ int multicast; /* indicator set for multicast add */ Tcl_Obj *groupsObj; /* list of the mcast groups */ } UdpState; + +#if defined(WIN32) && defined(_M_AMD64) +# define SOCKET_PRINTF_FMT "%I64u" +#else +# define SOCKET_PRINTF_FMT "%d" +#endif + EXTERN int Udp_Init(Tcl_Interp *interp); EXTERN int Udp_SafeInit(Tcl_Interp *interp); #endif Index: win/makefile.vc ================================================================== --- win/makefile.vc +++ win/makefile.vc @@ -13,20 +13,24 @@ # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # Copyright (c) 2001 ActiveState Corporation. # Copyright (c) 2001-2002 David Gravereaux. -# Copyright (c) 2003 Pat Thoyts +# Copyright (c) 2003-2006 Pat Thoyts # #------------------------------------------------------------------------- -# RCS: @(#)$Id: makefile.vc,v 1.9 2014/08/23 05:28:40 huubeikens Exp $ +# RCS: @(#)$Id$ #------------------------------------------------------------------------- -!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCToolkitInstallDir) +# Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) +# or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define +# VCINSTALLDIR instead. The MSVC Toolkit release defines yet another. +!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) && !defined(VCToolkitInstallDir) MSG = ^ -You will need to run vcvars32.bat from Developer Studio, first, to setup^ -the environment. Jump to this line to read the new instructions. +You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ +Platform SDK first to setup the environment. Jump to this line to read^ +the build instructions. !error $(MSG) !endif #------------------------------------------------------------------------------ # HOW TO USE this makefile: @@ -70,11 +74,11 @@ # msvcrt(d). This is useful for static embedding # support. # staticpkg = Effects the static option only to switch # tclshXX.exe to have the dde and reg extension linked # inside it. -# threads = Turns on full multithreading support. +# nothreads = Turns off multithreading support (not recommended) # thrdalloc = Use the thread allocator (shared global free pool). # symbols = Adds symbols for step debugging. # profile = Adds profiling hooks. Map file is assumed. # loimpact = Adds a flag for how NT treats the heap to keep memory # in use, low. This is said to impact alloc performance. @@ -86,15 +90,16 @@ # everything to nothing. # # memdbg = Enables the debugging memory allocator. # compdbg = Enables byte compilation logging. # -# MACHINE=(IX86|IA64|ALPHA) +# MACHINE=(IX86|IA64|ALPHA|AMD64) # Set the machine type used for the compiler, linker, and # resource compiler. This hook is needed to tell the tools # when alternate platforms are requested. IX86 is the default -# when not specified. +# when not specified. If the CPU environment variable has been +# set (ie: recent Platform SDK) then MACHINE is set from CPU. # # TMP_DIR= # OUT_DIR= # Hooks to allow the intermediate and output directories to be # changed. $(OUT_DIR) is assumed to be @@ -156,11 +161,10 @@ PROJECT = udp !include "rules.vc" DOTVERSION = 1.0.11 VERSION = $(DOTVERSION:.=) -STUBPREFIX = $(PROJECT)stub DLLOBJS = \ $(TMP_DIR)\udp_tcl.obj \ $(TMP_DIR)\tcludp.res @@ -181,88 +185,95 @@ PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) ### Make sure we use backslash only. PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) +LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_TCLDIR)\include -LIB_INSTALL_DIR = $(_TCLDIR)\lib ### The following paths CANNOT have spaces in them. GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc DEMODIR = $(ROOT)\demos TOOLSDIR = $(ROOT)\tools COMPATDIR = $(ROOT)\compat +EXPATDIR = $(ROOT)\expat + #--------------------------------------------------------------------- # Compile flags #--------------------------------------------------------------------- !if !$(DEBUG) !if $(OPTIMIZING) ### This cranks the optimization level to maximize speed -cdebug = -O2 -Op -Gs +cdebug = $(OPTIMIZATIONS) !else cdebug = !endif -!else if "$(MACHINE)" == "IA64" +!else if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" ### Warnings are too many, can't support warnings into errors. -cdebug = -Z7 -Od -GZ +cdebug = -Zi -Od $(DEBUGFLAGS) !else -cdebug = -Z7 -WX -Od -GZ +cdebug = -Zi -WX $(DEBUGFLAGS) !endif ### Declarations common to all compiler options -cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\ - -!if $(PENT_0F_ERRATA) -cflags = $(cflags) -QI0f -!endif - -!if $(ITAN_B_ERRATA) -cflags = $(cflags) -QIA64_Bx -!endif +cwarn = $(WARNINGS) -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -D _WINSOCK_DEPRECATED_NO_WARNINGS +cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\ !if $(MSVCRT) -!if $(DEBUG) +!if $(DEBUG) && !$(UNCHECKED) crt = -MDd !else crt = -MD !endif !else -!if $(DEBUG) +!if $(DEBUG) && !$(UNCHECKED) crt = -MTd !else crt = -MT !endif !endif -INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" -BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) +!if !$(STATIC_BUILD) +cflags = $(cflags) -DUSE_TCL_STUBS +!if defined(TKSTUBLIB) +cflags = $(cflags) -DUSE_TK_STUBS +!endif +!endif + +DEFS =-DHAVE_MEMMOVE=1 +DEFS_EXPAT =-DXMLIMPORT=__declspec(dllexport) +INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" -I"$(EXPATDIR)" $(TCL_INCLUDES) +BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -TCL_CFLAGS = -DUSE_TCL_STUBS -DPACKAGE_NAME="\"$(PROJECT)\"" \ +TCL_CFLAGS = -DPACKAGE_NAME="\"$(PROJECT)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ - $(BASE_CLFAGS) $(OPTDEFINES) + $(BASE_CFLAGS) $(OPTDEFINES) $(DEFS) #--------------------------------------------------------------------- # Link flags #--------------------------------------------------------------------- !if $(DEBUG) ldebug = -debug:full -debugtype:cv +!if $(MSVCRT) +ldebug = $(ldebug) -nodefaultlib:msvcrt +!endif !else ldebug = -release -opt:ref -opt:icf,3 !endif ### Declarations common to all linker options -lflags = -nologo -machine:$(MACHINE) $(ldebug) /verbose:lib +lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(PROFILE) lflags = $(lflags) -profile !endif @@ -279,18 +290,31 @@ !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows -baselibs = $(TCLSTUBLIB) ws2_32.lib +!if !$(STATIC_BUILD) +baselibs = $(TCLSTUBLIB) +!if defined(TKSTUBLIB) +baselibs = $(baselibs) $(TKSTUBLIB) +!endif +!endif + +baselibs = $(baselibs) ws2_32.lib + +# Avoid 'unresolved external symbol __security_cookie' errors. +# c.f. http://support.microsoft.com/?id=894573 +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" +baselibs = $(baselibs) bufferoverflowU.lib +!endif #--------------------------------------------------------------------- # TclTest flags #--------------------------------------------------------------------- !IF "$(TESTPAT)" != "" -TESTFLAGS = -file $(TESTPAT) +TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !ENDIF #--------------------------------------------------------------------- # Project specific targets (EDIT) #--------------------------------------------------------------------- @@ -327,17 +351,21 @@ setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) $(PRJLIB): $(DLLOBJS) - $(link32) $(dlllflags) -out:$@ $(baselibs) @<< +!if $(STATIC_BUILD) + $(lib32) -nologo -out:$@ @<< +$** +<< +!else + $(link32) $(dlllflags) -base:0x109E0000 -out:$@ $(baselibs) @<< $** << + $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp - -$(PRJSTUBLIB): $(PRJSTUBOBJS) - $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) +!endif #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- @@ -356,13 +384,13 @@ $< << {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ - -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ - -DDOTVERSION=\"$(DOTVERSION)\" \ - -DVERSION=\"$(VERSION)$(SUFX)\" \ + -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ + -DDOTVERSION=\"$(DOTVERSION)\" \ + -DVERSION=\"$(VERSION)$(SUFX)\" \ !if $(DEBUG) -d DEBUG \ !endif !if $(TCL_THREADS) -d TCL_THREADS \ @@ -398,19 +426,15 @@ @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist $(SCRIPT_INSTALL_DIR)\nul mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL install-libraries: - @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' -# @$(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" >NUL - @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl" -# Handcrafted pkgIndex for tcludp. -if {[info exists ::tcl_platform(debug)]} { - package ifneeded $(PROJECT) $(DOTVERSION) [list load [file join $$dir $(PROJECT)$(VERSION)g.$(EXT)]] -} else { - package ifneeded $(PROJECT) $(DOTVERSION) [list load [file join $$dir $(PROJECT)$(VERSION).$(EXT)]] -} + @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' + @if exist $(LIBDIR)\NUL $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" >NUL + @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' + @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl" + package ifneeded $(PROJECT) $(DOTVERSION) "[list load [file join $$dir $(PROJECT)$(VERSION)$(SUFX).$(EXT)] $(PROJECT)]" << install-docs: $(PRJDOCS) @echo Installing documentation to '$(DOC_INSTALL_DIR)' @if not exist $(DOC_INSTALL_DIR)\NUL mkdir "$(DOC_INSTALL_DIR)" @@ -426,13 +450,16 @@ # Clean up #--------------------------------------------------------------------- clean: @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) - @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc + @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc + @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i + @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x + @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch realclean: clean @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) distclean: realclean @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj Index: win/nmakehlp.c ================================================================== --- win/nmakehlp.c +++ win/nmakehlp.c @@ -1,105 +1,187 @@ -/* ---------------------------------------------------------------------------- +/* + * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * * Copyright (c) 2002 by David Gravereaux. - * Copyright (c) 2003 by Patrick Thoyts + * Copyright (c) 2006 by Pat Thoyts * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: nmakehlp.c,v 1.2 2004/11/22 23:48:48 patthoyts Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ + +#define _CRT_SECURE_NO_DEPRECATE #include -#include +#define NO_SHLWAPI_GDI +#define NO_SHLWAPI_STREAM +#define NO_SHLWAPI_REG +#include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") +#pragma comment (lib, "shlwapi.lib") +#include +#include + +/* + * This library is required for x64 builds with _some_ versions of MSVC + */ +#if defined(_M_IA64) || defined(_M_AMD64) +#if _MSC_VER >= 1400 && _MSC_VER < 1500 +#pragma comment(lib, "bufferoverflowU") +#endif +#endif + +/* ISO hack for dumb VC++ */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + /* protos */ -int CheckForCompilerFeature (const char *option); -int CheckForLinkerFeature (const char *option); -int IsIn (const char *string, const char *substring); -DWORD WINAPI ReadFromPipe (LPVOID args); -int GetVersionFromHeader(const char *tclh, const char *tkh); + +static int CheckForCompilerFeature(const char *option); +static int CheckForLinkerFeature(const char **options, int count); +static int IsIn(const char *string, const char *substring); +static int SubstituteFile(const char *substs, const char *filename); +static int QualifyPath(const char *path); +static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); +static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ + +#define CHUNK 25 +#define STATICBUFFERSIZE 1000 typedef struct { HANDLE pipe; - char buffer[1000]; + char buffer[STATICBUFFERSIZE]; } pipeinfo; pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; + +/* + * exitcodes: 0 == no, 1 == yes, 2 == error + */ - - -/* exitcodes: 0 == no, 1 == yes, 2 == error */ int -main (int argc, char *argv[]) +main( + int argc, + char *argv[]) { char msg[300]; DWORD dwWritten; int chars; + /* + * Make sure children (cl.exe and link.exe) are kept quiet. + */ + + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + /* + * Make sure the compiler and linker aren't effected by the outside world. + */ + + SetEnvironmentVariable("CL", ""); + SetEnvironmentVariable("LINK", ""); + if (argc > 1 && *argv[1] == '-') { switch (*(argv[1]+1)) { case 'c': if (argc != 3) { - chars = wsprintf(msg, "usage: %s -c \n" + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c \n" "Tests for whether cl.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': - if (argc != 3) { - chars = wsprintf(msg, "usage: %s -l \n" + if (argc < 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -l ? ...?\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } - return CheckForLinkerFeature(argv[2]); + return CheckForLinkerFeature(&argv[2], argc-2); case 'f': if (argc == 2) { - chars = wsprintf(msg, "usage: %s -f \n" - "Find a substring within another\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -f \n" + "Find a substring within another\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } else if (argc == 3) { - /* if the string is blank, there is no match */ + /* + * If the string is blank, there is no match. + */ + return 0; } else { return IsIn(argv[2], argv[3]); } - case 'v': + case 's': + if (argc == 2) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -s \n" + "Perform a set of string map type substutitions on a file\n" + "exitcodes: 0\n", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return SubstituteFile(argv[2], argv[3]); + case 'V': if (argc != 4) { - chars = wsprintf(msg, "usage: %s -v \n" - "Search for versions from the tcl and tk headers.", + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -V filename matchstring\n" + "Extract a version from a file:\n" + "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 0; } - return GetVersionFromHeader(argv[2], argv[3]); + printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0')); + return 0; + case 'Q': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -Q path\n" + "Emit the fully qualified path\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return QualifyPath(argv[2]); } } - chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n" + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } - -int -CheckForCompilerFeature (const char *option) + +static int +CheckForCompilerFeature( + const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; @@ -119,28 +201,48 @@ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; - /* create a non-inheritible pipe. */ + /* + * Create a non-inheritible pipe. + */ + CreatePipe(&Out.pipe, &h, &sa, 0); - /* dupe the write side, make it inheritible, and close the original. */ - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + /* + * Dupe the write side, make it inheritible, and close the original. + */ - /* Same as above, but for the error side. */ + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ + CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* base command line */ - strcpy(cmdline, "cl.exe -nologo -c -TC -Fdtemp "); - /* append our option for testing */ - strcat(cmdline, option); - /* filename to compile, which exists, but is nothing and empty. */ - strcat(cmdline, " nul"); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); + + /* + * Append our option for testing + */ + + lstrcat(cmdline, option); + + /* + * Filename to compile, which exists, but is nothing and empty. + */ + + lstrcat(cmdline, " .\\nul"); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ @@ -152,58 +254,79 @@ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); - int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars], + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } - /* close our references to the write handles that have now been inherited. */ + /* + * Close our references to the write handles that have now been inherited. + */ + CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); - /* start the pipe reader threads. */ + /* + * Start the pipe reader threads. + */ + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - /* block waiting for the process to end. */ + /* + * Block waiting for the process to end. + */ + WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); - /* clean up temporary files before returning */ - DeleteFile("temp.idb"); - DeleteFile("temp.pdb"); + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ - /* wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); - /* look for the commandline warning code in both streams. */ - return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL); + /* + * Look for the commandline warning code in both streams. + * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. + */ + + return !(strstr(Out.buffer, "D4002") != NULL + || strstr(Err.buffer, "D4002") != NULL + || strstr(Out.buffer, "D9002") != NULL + || strstr(Err.buffer, "D9002") != NULL + || strstr(Out.buffer, "D2021") != NULL + || strstr(Err.buffer, "D2021") != NULL); } - -int -CheckForLinkerFeature (const char *option) + +static int +CheckForLinkerFeature( + const char **options, + int count) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; - char cmdline[100]; + int i; + char cmdline[255]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); @@ -214,28 +337,46 @@ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; - /* create a non-inheritible pipe. */ + /* + * Create a non-inheritible pipe. + */ + CreatePipe(&Out.pipe, &h, &sa, 0); - /* dupe the write side, make it inheritible, and close the original. */ - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - /* Same as above, but for the error side. */ + /* + * Same as above, but for the error side. + */ + CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* base command line */ - strcpy(cmdline, "link.exe -nologo "); - /* append our option for testing */ - strcat(cmdline, option); - /* filename to compile, which exists, but is nothing and empty. */ -// strcat(cmdline, " nul"); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "link.exe -nologo "); + + /* + * Append our option for testing. + */ + + for (i = 0; i < count; i++) { + lstrcat(cmdline, " \""); + lstrcat(cmdline, options[i]); + lstrcat(cmdline, "\""); + } ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ @@ -247,109 +388,318 @@ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); - int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars], + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } - /* close our references to the write handles that have now been inherited. */ + /* + * Close our references to the write handles that have now been inherited. + */ + CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); - /* start the pipe reader threads. */ + /* + * Start the pipe reader threads. + */ + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - /* block waiting for the process to end. */ + /* + * Block waiting for the process to end. + */ + WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); - /* wait for our pipe to get done reading, should it be a little slow. */ + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); - /* look for the commandline warning code in the stderr stream. */ - return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL); + /* + * Look for the commandline warning code in the stderr stream. + */ + + return !(strstr(Out.buffer, "LNK1117") != NULL || + strstr(Err.buffer, "LNK1117") != NULL || + strstr(Out.buffer, "LNK4044") != NULL || + strstr(Err.buffer, "LNK4044") != NULL || + strstr(Out.buffer, "LNK4224") != NULL || + strstr(Err.buffer, "LNK4224") != NULL); } - -DWORD WINAPI -ReadFromPipe (LPVOID args) + +static DWORD WINAPI +ReadFromPipe( + LPVOID args) { pipeinfo *pi = (pipeinfo *) args; char *lastBuf = pi->buffer; DWORD dwRead; BOOL ok; -again: - ok = ReadFile(pi->pipe, lastBuf, 25, &dwRead, 0L); + again: + if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { + CloseHandle(pi->pipe); + return (DWORD)-1; + } + ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); if (!ok || dwRead == 0) { CloseHandle(pi->pipe); return 0; } lastBuf += dwRead; goto again; return 0; /* makes the compiler happy */ } - -int -IsIn (const char *string, const char *substring) + +static int +IsIn( + const char *string, + const char *substring) { return (strstr(string, substring) != NULL); } - - -static double -ReadVersionFromHeader(const char *file, const char *macro) -{ - double d = 0.0; - CHAR szBuffer[100]; - LPSTR p; - DWORD cbBuffer = 100; - FILE *fp = fopen(file, "r"); - if (fp != NULL) { - while (fgets(szBuffer, cbBuffer, fp) != NULL) { - if ((p = strstr(szBuffer, macro)) != NULL) { - while (*p && !isdigit(*p)) ++p; - d = strtod(p, NULL); + +/* + * GetVersionFromFile -- + * Looks for a match string in a file and then returns the version + * following the match where a version is anything acceptable to + * package provide or package ifneeded. + */ + +static const char * +GetVersionFromFile( + const char *filename, + const char *match, + int numdots) +{ + size_t cbBuffer = 100; + static char szBuffer[100]; + char *szResult = NULL; + FILE *fp = fopen(filename, "rt"); + + if (fp != NULL) { + /* + * Read data until we see our match string. + */ + + while (fgets(szBuffer, cbBuffer, fp) != NULL) { + LPSTR p, q; + + p = strstr(szBuffer, match); + if (p != NULL) { + /* + * Skip to first digit after the match. + */ + + p += strlen(match); + while (*p && !isdigit(*p)) { + ++p; + } + + /* + * Find ending whitespace. + */ + + q = p; + while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) + && (!strchr("ab", q[-1])) || --numdots))) { + ++q; + } + + memcpy(szBuffer, p, q - p); + szBuffer[q-p] = 0; + szResult = szBuffer; break; } } fclose(fp); } - return d; -} - -int -GetVersionFromHeader(const char *tclh, const char *tkh) -{ - double dTcl = 0.0, dTk = 0.0; - - if (tclh != NULL) - dTcl = ReadVersionFromHeader(tclh, "TCL_VERSION"); - if (tkh != NULL) - dTk = ReadVersionFromHeader(tkh, "TK_VERSION"); - - if (dTcl > 0 || dTk > 0) { - FILE *ofp = fopen("version.vc", "w"); - if (dTcl > 0) - fprintf(ofp, "TCL_DOTVERSION\t= %0.1f\nTCL_VERSION\t= %u\n", - dTcl, (int)(dTcl * 10.0)); - if (dTk > 0) - fprintf(ofp, "TK_DOTVERSION\t= %0.1f\nTK_VERSION\t= %u\n", - dTk, (int)(dTk * 10.0)); - fclose(ofp); - return 0; - } - return 1; -} + return szResult; +} + +/* + * List helpers for the SubstituteFile function + */ + +typedef struct list_item_t { + struct list_item_t *nextPtr; + char * key; + char * value; +} list_item_t; + +/* insert a list item into the list (list may be null) */ +static list_item_t * +list_insert(list_item_t **listPtrPtr, const char *key, const char *value) +{ + list_item_t *itemPtr = malloc(sizeof(list_item_t)); + if (itemPtr) { + itemPtr->key = strdup(key); + itemPtr->value = strdup(value); + itemPtr->nextPtr = NULL; + + while(*listPtrPtr) { + listPtrPtr = &(*listPtrPtr)->nextPtr; + } + *listPtrPtr = itemPtr; + } + return itemPtr; +} + +static void +list_free(list_item_t **listPtrPtr) +{ + list_item_t *tmpPtr, *listPtr = *listPtrPtr; + while (listPtr) { + tmpPtr = listPtr; + listPtr = listPtr->nextPtr; + free(tmpPtr->key); + free(tmpPtr->value); + free(tmpPtr); + } +} + +/* + * SubstituteFile -- + * As windows doesn't provide anything useful like sed and it's unreliable + * to use the tclsh you are building against (consider x-platform builds - + * eg compiling AMD64 target from IX86) we provide a simple substitution + * option here to handle autoconf style substitutions. + * The substitution file is whitespace and line delimited. The file should + * consist of lines matching the regular expression: + * \s*\S+\s+\S*$ + * + * Usage is something like: + * nmakehlp -S << $** > $@ + * @PACKAGE_NAME@ $(PACKAGE_NAME) + * @PACKAGE_VERSION@ $(PACKAGE_VERSION) + * << + */ + +static int +SubstituteFile( + const char *substitutions, + const char *filename) +{ + size_t cbBuffer = 1024; + static char szBuffer[1024], szCopy[1024]; + char *szResult = NULL; + list_item_t *substPtr = NULL; + FILE *fp, *sp; + + fp = fopen(filename, "rt"); + if (fp != NULL) { + + /* + * Build a list of substutitions from the first filename + */ + + sp = fopen(substitutions, "rt"); + if (sp != NULL) { + while (fgets(szBuffer, cbBuffer, sp) != NULL) { + unsigned char *ks, *ke, *vs, *ve; + ks = (unsigned char*)szBuffer; + while (ks && *ks && isspace(*ks)) ++ks; + ke = ks; + while (ke && *ke && !isspace(*ke)) ++ke; + vs = ke; + while (vs && *vs && isspace(*vs)) ++vs; + ve = vs; + while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; + *ke = 0, *ve = 0; + list_insert(&substPtr, (char*)ks, (char*)vs); + } + fclose(sp); + } + + /* debug: dump the list */ +#ifdef _DEBUG + { + int n = 0; + list_item_t *p = NULL; + for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { + fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); + } + } +#endif + + /* + * Run the substitutions over each line of the input + */ + + while (fgets(szBuffer, cbBuffer, fp) != NULL) { + list_item_t *p = NULL; + for (p = substPtr; p != NULL; p = p->nextPtr) { + char *m = strstr(szBuffer, p->key); + if (m) { + char *cp, *op, *sp; + cp = szCopy; + op = szBuffer; + while (op != m) *cp++ = *op++; + sp = p->value; + while (sp && *sp) *cp++ = *sp++; + op += strlen(p->key); + while (*op) *cp++ = *op++; + *cp = 0; + memcpy(szBuffer, szCopy, sizeof(szCopy)); + } + } + printf(szBuffer); + } + + list_free(&substPtr); + } + fclose(fp); + return 0; +} + +/* + * QualifyPath -- + * + * This composes the current working directory with a provided path + * and returns the fully qualified and normalized path. + * Mostly needed to setup paths for testing. + */ + +static int +QualifyPath( + const char *szPath) +{ + char szCwd[MAX_PATH + 1]; + char szTmp[MAX_PATH + 1]; + char *p; + GetCurrentDirectory(MAX_PATH, szCwd); + while ((p = strchr(szPath, '/')) && *p) + *p = '\\'; + PathCombine(szTmp, szCwd, szPath); + PathCanonicalize(szCwd, szTmp); + printf("%s\n", szCwd); + return 0; +} + +/* + * Local variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ Index: win/rules.vc ================================================================== --- win/rules.vc +++ win/rules.vc @@ -2,21 +2,15 @@ # rules.vc -- # # Microsoft Visual C++ makefile include for decoding the commandline # macros. This file does not need editing to build Tcl. # -# This version is modified from the Tcl source version to support -# building extensions using nmake. -# # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. -# -# Copyright (c) 2001-2002 David Gravereaux. -# Copyright (c) 2003 Patrick Thoyts # -#------------------------------------------------------------------------------ -# RCS: @(#) $Id: rules.vc,v 1.3 2005/05/17 14:54:56 patthoyts Exp $ +# Copyright (c) 2001-2003 David Gravereaux. +# Copyright (c) 2003-2008 Patrick Thoyts #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 @@ -31,146 +25,273 @@ !else ### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !endif -!ifndef MACHINE -MACHINE = IX86 -!endif - -!ifndef CFG_ENCODING -CFG_ENCODING = \"cp1252\" -!endif - #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right # "delete all" method. #---------------------------------------------------------- !if "$(OS)" == "Windows_NT" RMDIR = rmdir /S /Q +ERRNULL = 2>NUL !if ![ver | find "4.0" > nul] -CPY = echo y | xcopy /i +CPY = echo y | xcopy /i >NUL +COPY = copy >NUL !else -CPY = xcopy /i /y +CPY = xcopy /i /y >NUL +COPY = copy /y >NUL !endif -!else -CPY = xcopy /i +!else # "$(OS)" != "Windows_NT" +CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here. +COPY = copy >_JUNK.OUT # On Win98 NUL does not work here. RMDIR = deltree /Y +NULL = \NUL # Used in testing directory existence +ERRNULL = >NUL # Win9x shell cannot redirect stderr +!endif +MKDIR = mkdir + +#------------------------------------------------------------------------------ +# Determine the host and target architectures and compiler version. +#------------------------------------------------------------------------------ + +_HASH=^# +_VC_MANIFEST_EMBED_EXE= +_VC_MANIFEST_EMBED_DLL= +VCVER=0 +!if ![echo VCVERSION=_MSC_VER > vercl.x] \ + && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ + && ![echo ARCH=IX86 >> vercl.x] \ + && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ + && ![echo ARCH=AMD64 >> vercl.x] \ + && ![echo $(_HASH)endif >> vercl.x] \ + && ![cl -nologo -TC -P vercl.x $(ERRNULL)] +!include vercl.i +!if ![echo VCVER= ^\> vercl.vc] \ + && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] +!include vercl.vc +!endif +!endif +!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc] !endif +!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] +NATIVE_ARCH=IX86 +!else +NATIVE_ARCH=AMD64 +!endif + +# Since MSVC8 we must deal with manifest resources. +!if $(VCVERSION) >= 1400 +_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 +_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 +!endif + +!ifndef MACHINE +MACHINE=$(ARCH) +!endif + +!ifndef CFG_ENCODING +CFG_ENCODING = \"cp1252\" +!endif !message =============================================================================== #---------------------------------------------------------- # build the helper app we need to overcome nmake's limiting # environment. #---------------------------------------------------------- !if !exist(nmakehlp.exe) -!if [$(cc32) -nologo -ML nmakehlp.c -link -subsystem:console > nul] +!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] !endif !endif #---------------------------------------------------------- # Test for compiler features #---------------------------------------------------------- ### test for optimizations -!if [nmakehlp -c -Otip] +!if [nmakehlp -c -Ot] !message *** Compiler has 'Optimizations' OPTIMIZING = 1 !else -!message *** Compiler doesn't have 'Optimizations' +!message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif + +OPTIMIZATIONS = + +!if [nmakehlp -c -Ot] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot +!endif + +!if [nmakehlp -c -Oi] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi +!endif + +!if [nmakehlp -c -Op] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Op +!endif + +!if [nmakehlp -c -fp:strict] +OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict +!endif + +!if [nmakehlp -c -Gs] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs +!endif + +!if [nmakehlp -c -GS] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GS +!endif + +!if [nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GL +!endif + +DEBUGFLAGS = + +!if [nmakehlp -c -RTC1] +DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 +!elseif [nmakehlp -c -GZ] +DEBUGFLAGS = $(DEBUGFLAGS) -GZ +!endif + +COMPILERFLAGS =-W3 /DUNICODE /D_UNICODE /D_ATL_XP_TARGETING + +# In v13 -GL and -YX are incompatible. +!if [nmakehlp -c -YX] +!if ![nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -YX +!endif +!endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' -PENT_0F_ERRATA = 1 -!else -!message *** Compiler doesn't have 'Pentium 0x0f fix' -PENT_0F_ERRATA = 0 -!endif -### test for -align:4096, when align:512 will do. -!if [nmakehlp -l -opt:nowin98] -!message *** Linker has 'Win98 alignment problem' -ALIGN98_HACK = 1 -!else -!message *** Linker doesn't have 'Win98 alignment problem' -ALIGN98_HACK = 0 -!endif -!else -PENT_0F_ERRATA = 0 -ALIGN98_HACK = 0 +COMPILERFLAGS = $(COMPILERFLAGS) -QI0f +!else +!message *** Compiler does not have 'Pentium 0x0f fix' +!endif !endif !if "$(MACHINE)" == "IA64" ### test for Itanium errata !if [nmakehlp -c -QIA64_Bx] !message *** Compiler has 'B-stepping errata workarounds' -ITAN_B_ERRATA = 1 +COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx +!else +!message *** Compiler does not have 'B-stepping errata workarounds' +!endif +!endif + +# Prevents "LNK1561: entry point must be defined" error compiling from VS-IDE: +!ifndef LINKER_TESTFLAGS +LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmhlp-out.txt +!endif + +!if "$(MACHINE)" == "IX86" +### test for -align:4096, when align:512 will do. +!if [nmakehlp -l -opt:nowin98 $(LINKER_TESTFLAGS)] +!message *** Linker has 'Win98 alignment problem' +ALIGN98_HACK = 1 !else -!message *** Compiler doesn't have 'B-stepping errata workarounds' -ITAN_B_ERRATA = 0 +!message *** Linker does not have 'Win98 alignment problem' +ALIGN98_HACK = 0 !endif !else -ITAN_B_ERRATA = 0 +ALIGN98_HACK = 0 +!endif + +LINKERFLAGS = + +!if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] +LINKERFLAGS =-ltcg !endif #---------------------------------------------------------- # Decode the options requested. #---------------------------------------------------------- !if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] STATIC_BUILD = 0 -TCL_THREADS = 0 +TCL_THREADS = 1 DEBUG = 0 +SYMBOLS = 0 PROFILE = 0 -MSVCRT = 0 +PGO = 0 +MSVCRT = 1 LOIMPACT = 0 TCL_USE_STATIC_PACKAGES = 0 -USE_THREAD_ALLOC = 0 +USE_THREAD_ALLOC = 1 +UNCHECKED = 0 !else !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !else STATIC_BUILD = 0 !endif +!if [nmakehlp -f $(OPTS) "nomsvcrt"] +!message *** Doing nomsvcrt +MSVCRT = 0 +!else !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else +!if !$(STATIC_BUILD) +MSVCRT = 1 +!else MSVCRT = 0 !endif -!if [nmakehlp -f $(OPTS) "staticpkg"] +!endif +!endif +!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif -!if [nmakehlp -f $(OPTS) "threads"] -!message *** Doing threads +!if [nmakehlp -f $(OPTS) "nothreads"] +!message *** Compile explicitly for non-threaded tcl +TCL_THREADS = 0 +USE_THREAD_ALLOC= 0 +!else TCL_THREADS = 1 -!else -TCL_THREADS = 0 +USE_THREAD_ALLOC= 1 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 +!endif +!if [nmakehlp -f $(OPTS) "pdbs"] +!message *** Doing pdbs +SYMBOLS = 1 +!else +SYMBOLS = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 +!endif +!if [nmakehlp -f $(OPTS) "pgi"] +!message *** Doing profile guided optimization instrumentation +PGO = 1 +!elseif [nmakehlp -f $(OPTS) "pgo"] +!message *** Doing profile guided optimization +PGO = 2 +!else +PGO = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Doing loimpact LOIMPACT = 1 !else @@ -177,51 +298,66 @@ LOIMPACT = 0 !endif !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 -!else +!endif +!if [nmakehlp -f $(OPTS) "tclalloc"] +!message *** Doing tclalloc USE_THREAD_ALLOC = 0 !endif -!endif - - -!if !$(STATIC_BUILD) -# Make sure we don't build overly fat DLLs. -MSVCRT = 1 -# We shouldn't statically put the extensions inside the shell when dynamic. -TCL_USE_STATIC_PACKAGES = 0 -!endif - +!if [nmakehlp -f $(OPTS) "unchecked"] +!message *** Doing unchecked +UNCHECKED = 1 +!else +UNCHECKED = 0 +!endif +!endif #---------------------------------------------------------- # Figure-out how to name our intermediate and output directories. # We wouldn't want different builds to use the same .obj files # by accident. #---------------------------------------------------------- +#---------------------------------------- +# Naming convention: +# t = full thread support. +# s = static library (as opposed to an +# import library) +# g = linked to the debug enabled C +# run-time. +# x = special static build when it +# links to the dynamic C run-time. +#---------------------------------------- SUFX = tsgx !if $(DEBUG) BUILDDIRTOP = Debug -DBGX = g !else BUILDDIRTOP = Release -DBGX = +!endif + +!if "$(MACHINE)" != "IX86" +BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) +!endif +!if $(VCVER) > 6 +BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) +!endif + +!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll -!if $(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) -!endif !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) @@ -266,19 +402,66 @@ !else TCL_COMPILE_DEBUG = 0 !endif !endif + +#---------------------------------------------------------- +# Decode the checks requested. +#---------------------------------------------------------- + +!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] +TCL_NO_DEPRECATED = 0 +WARNINGS = -W3 +!else +!if [nmakehlp -f $(CHECKS) "nodep"] +!message *** Doing nodep check +TCL_NO_DEPRECATED = 1 +!else +TCL_NO_DEPRECATED = 0 +!endif +!if [nmakehlp -f $(CHECKS) "fullwarn"] +!message *** Doing full warnings check +WARNINGS = -W4 +!if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS) -warn:3 +!endif +!else +WARNINGS = -W3 +!endif +!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] +!message *** Doing 64bit portability warnings +WARNINGS = $(WARNINGS) -Wp64 +!endif +!endif + +!if $(PGO) > 1 +!if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif +!elseif $(PGO) > 0 +!if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif +!endif #---------------------------------------------------------- # Set our defines now armed with our options. #---------------------------------------------------------- -OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) +OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS !if $(TCL_MEM_DEBUG) -OPTDEFINES = -DTCL_MEM_DEBUG +OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) @@ -288,29 +471,39 @@ !endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif +!if $(TCL_NO_DEPRECATED) +OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED +!endif -!if $(DEBUG) -OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DEBUG -!elseif $(OPTIMIZING) +!if !$(DEBUG) +OPTDEFINES = $(OPTDEFINES) -DNDEBUG +!if $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED +!endif !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif -!if "$(MACHINE)" == "IA64" +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif - +!if $(VCVERSION) < 1300 +OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 +!endif #---------------------------------------------------------- -# Get common info used when building extensions. +# Locate the Tcl headers to build against #---------------------------------------------------------- -!if "$(PROJECT)" != "tcl" +!if "$(PROJECT)" == "tcl" + +_TCL_H = ..\generic\tcl.h + +!else # If INSTALLDIR set to tcl root dir then reset to the lib dir. !if exist("$(_INSTALLDIR)\include\tcl.h") _INSTALLDIR=$(_INSTALLDIR)\lib !endif @@ -338,40 +531,104 @@ MSG =^ Failed to find tcl.h. The TCLDIR macro does not appear correct. !error $(MSG) !endif !endif +!endif + +#-------------------------------------------------------------- +# Extract various version numbers from tcl headers +# The generated file is then included in the makefile. +#-------------------------------------------------------------- + +!if [echo REM = This file is generated from rules.vc > versions.vc] +!endif +!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TCL_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] +!endif +!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] +!endif -!if [nmakehlp -v "$(_TCL_H)" ""] == 0 -!include version.vc -!else -TCL_DOTVERSION = 8.5 -TCL_VERSION = $(TCL_DOTVERSION:.=) +# If building the tcl core then we need additional package versions +!if "$(PROJECT)" == "tcl" +!if [echo PKG_HTTP_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc] +!endif +!if [echo PKG_TCLTEST_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc] +!endif +!if [echo PKG_MSGCAT_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc] +!endif +!if [echo PKG_PLATFORM_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc] +!endif +!if [echo PKG_SHELL_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc] +!endif +!if [echo PKG_DDE_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc] +!endif +!if [echo PKG_REG_VER =\>> versions.vc] \ + && [nmakehlp -V ..\library\reg\pkgIndex.tcl registry >> versions.vc] +!endif !endif +!include versions.vc + +#-------------------------------------------------------------- +# Setup tcl version dependent stuff headers +#-------------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" + +TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) + !if $(TCLINSTALL) TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" +!if !exist($(TCLSH)) && $(TCL_THREADS) +TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION).exe" +!endif TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib" TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" TCL_LIBRARY = $(_TCLDIR)\lib +TCLREGLIB = "$(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib" +TCLDDELIB = "$(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib" +COFFBASE = \must\have\tcl\sources\to\build\this\target +TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target TCL_INCLUDES = -I"$(_TCLDIR)\include" !else TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" +!if !exist($(TCLSH)) && $(TCL_THREADS) +TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION).exe" +!endif TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib" TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib" TCL_LIBRARY = $(_TCLDIR)\library +TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib" +TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib" +COFFBASE = "$(_TCLDIR)\win\coffbase.txt" +TCLTOOLSDIR = $(_TCLDIR)\tools TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" !endif !endif -#---------------------------------------------------------- -# Get Tk info for building extensions. -#---------------------------------------------------------- +#------------------------------------------------------------------------- +# Locate the Tk headers to build against +#------------------------------------------------------------------------- + +!if "$(PROJECT)" == "tk" +_TK_H = ..\generic\tk.h +_INSTALLDIR = $(_INSTALLDIR)\.. +!endif -!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" - +!ifdef PROJECT_REQUIRES_TK !if !defined(TKDIR) !if exist("$(_INSTALLDIR)\..\include\tk.h") TKINSTALL = 1 _TKDIR = $(_INSTALLDIR)\.. _TK_H = $(_TKDIR)\include\tk.h @@ -379,14 +636,10 @@ !elseif exist("$(_TCLDIR)\include\tk.h") TKINSTALL = 1 _TKDIR = $(_TCLDIR) _TK_H = $(_TKDIR)\include\tk.h TKDIR = $(_TKDIR) -!else -MSG =^ -Failed to find tk.h. Set the TKDIR macro. -!error $(MSG) !endif !else _TKDIR = $(TKDIR:/=\) !if exist("$(_TKDIR)\include\tk.h") TKINSTALL = 1 @@ -398,18 +651,34 @@ MSG =^ Failed to find tk.h. The TKDIR macro does not appear correct. !error $(MSG) !endif !endif +!endif + +#------------------------------------------------------------------------- +# Extract Tk version numbers +#------------------------------------------------------------------------- + +!if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk" -!if [nmakehlp -v "$(_TCL_H)" "$(_TK_H)"] == 0 -!include version.vc -!else -TK_DOTVERSION = 8.5 -TK_VERSION = $(TK_DOTVERSION:.=) +!if [echo TK_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TK_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] +!endif +!if [echo TK_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] !endif +!include versions.vc + +TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) +TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) + +!if "$(PROJECT)" != "tk" !if $(TKINSTALL) WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe" TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib" TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" TK_INCLUDES = -I"$(_TKDIR)\include" @@ -417,20 +686,23 @@ WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe" TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib" TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib" TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" !endif - !endif - +!endif #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Optional defines are '$(OPTDEFINES)' +!message *** Compiler version $(VCVER). Target machine is $(MACHINE) +!message *** Host architecture is $(NATIVE_ARCH) +!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)' +!message *** Link options '$(LINKERFLAGS)' !endif