From: patthoyts Date: Mon, 9 Feb 2004 12:03:40 +0000 (+0000) Subject: Added the standard windows nmake makefiles from the sampleextension project. X-Git-Tag: root-dev-2~4 X-Git-Url: http://privyetmir.co.uk/gitweb.cgi?a=commitdiff_plain;h=36e819830e620164acc97cf1ed371a5e7e24a400;p=tcludp Added the standard windows nmake makefiles from the sampleextension project. --- diff --git a/win/makefile.vc b/win/makefile.vc new file mode 100644 index 0000000..e909bd9 --- /dev/null +++ b/win/makefile.vc @@ -0,0 +1,391 @@ +# makefile.vc -- -*- Makefile -*- +# +# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) +# +# This makefile is based upon the Tcl 8.4 Makefile.vc and modified to +# make it suitable as a general package makefile. Look for the word EDIT +# which marks sections that may need modification. As a minumum you will +# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values +# relevant to your package. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# 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 +# +#------------------------------------------------------------------------- +# RCS: @(#)$Id$ +#------------------------------------------------------------------------- + +!if "$(MSVCDIR)" == "" +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. +!error $(MSG) +!endif + +#------------------------------------------------------------------------------ +# HOW TO USE this makefile: +# +# 1) It is now necessary to have %MSVCDir% set in the environment. This is +# used as a check to see if vcvars32.bat had been run prior to running +# nmake or during the installation of Microsoft Visual C++, MSVCDir had +# been set globally and the PATH adjusted. Either way is valid. +# +# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin +# directory to setup the proper environment, if needed, for your current +# setup. This is a needed bootstrap requirement and allows the swapping of +# different environments to be easier. +# +# 2) To use the Platform SDK (not expressly needed), run setenv.bat after +# vcvars32.bat according to the instructions for it. This can also turn on +# the 64-bit compiler, if your SDK has it. +# +# 3) Targets are: +# all -- Builds everything. +# -- Builds the project (eg: nmake sample) +# test -- Builds and runs the test suite. +# install -- Installs the built binaries and libraries to $(INSTALLDIR) +# in an appropriate subdirectory. +# clean/realclean/distclean -- varying levels of cleaning. +# +# 4) Macros usable on the commandline: +# INSTALLDIR= +# Sets where to install Tcl from the built binaries. +# C:\Progra~1\Tcl is assumed when not specified. +# +# OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none +# Sets special options for the core. The default is for none. +# Any combination of the above may be used (comma separated). +# 'none' will over-ride everything to nothing. +# +# static = Builds a static library of the core instead of a +# dll. The shell will be static (and large), as well. +# msvcrt = Effects the static option only to switch it from +# using libcmt(d) as the C runtime [by default] to +# 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. +# 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. +# +# STATS=memdbg,compdbg,none +# Sets optional memory and bytecode compiler debugging code added +# to the core. The default is for none. Any combination of the +# above may be used (comma separated). 'none' will over-ride +# everything to nothing. +# +# memdbg = Enables the debugging memory allocator. +# compdbg = Enables byte compilation logging. +# +# MACHINE=(IX86|IA64|ALPHA) +# 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. +# +# TMP_DIR= +# OUT_DIR= +# Hooks to allow the intermediate and output directories to be +# changed. $(OUT_DIR) is assumed to be +# $(BINROOT)\(Release|Debug) based on if symbols are requested. +# $(TMP_DIR) will de $(OUT_DIR)\ by default. +# +# TESTPAT= +# Reads the tests requested to be run from this file. +# +# CFG_ENCODING=encoding +# name of encoding for configuration information. Defaults +# to cp1252 +# +# 5) Examples: +# +# Basic syntax of calling nmake looks like this: +# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] +# +# Standard (no frills) +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>nmake -f makefile.vc all +# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl +# +# Building for Win64 +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL +# Targeting Windows pre64 RETAIL +# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64 +# +#------------------------------------------------------------------------------ +#============================================================================== +############################################################################### +#------------------------------------------------------------------------------ + +!if !exist("makefile.vc") +MSG = ^ +You must run this makefile only from the directory it is in.^ +Please `cd` to its location first. +!error $(MSG) +!endif + +#------------------------------------------------------------------------- +# Project specific information (EDIT) +# +# You should edit this with the name and version of your project. This +# information is used to generate the name of the package library and +# it's install location. +# +# For example, the sample extension is going to build sample04.dll and +# would install it into $(INSTALLDIR)\lib\sample04 +# +# You need to specify the object files that need to be linked into your +# binary here. +# +#------------------------------------------------------------------------- + +PROJECT = udp +!include "rules.vc" + +DOTVERSION = 1.0.6 +VERSION = $(DOTVERSION:.=) +STUBPREFIX = $(PROJECT)stub + +DLLOBJS = \ + $(TMP_DIR)\udp_tcl.obj \ + $(TMP_DIR)\tcludp.res + +#------------------------------------------------------------------------- +# Target names and paths ( shouldn't need changing ) +#------------------------------------------------------------------------- + +BINROOT = . +ROOT = .. + +PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib +PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) +PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) + +PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib +PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) + +### Make sure we use backslash only. +LIB_INSTALL_DIR = $(_INSTALLDIR)\lib +BIN_INSTALL_DIR = $(_INSTALLDIR)\bin +DOC_INSTALL_DIR = $(_INSTALLDIR)\doc +SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(DOTVERSION) +INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include + +### The following paths CANNOT have spaces in them. +GENERICDIR = $(ROOT)\generic +WINDIR = $(ROOT)\win +LIBDIR = $(ROOT)\library +DOCDIR = $(ROOT)\doc +TOOLSDIR = $(ROOT)\tools +COMPATDIR = $(ROOT)\compat + +### Find a tclsh for testing and installation. +!if !exist("$(TCLSH)") +TCLSH = $(BIN_INSTALL_DIR)\tclsh$(TCL_VERSION).exe +!endif + +#--------------------------------------------------------------------- +# Compile flags +#--------------------------------------------------------------------- + +!if !$(DEBUG) +!if $(OPTIMIZING) +### This cranks the optimization level to maximize speed +cdebug = -O2 -Op -Gs +!else +cdebug = +!endif +!else if "$(MACHINE)" == "IA64" +### Warnings are too many, can't support warnings into errors. +cdebug = -Z7 -Od +!else +cdebug = -Z7 -WX -Od +!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 + +!if $(MSVCRT) +!if $(DEBUG) +crt = -MDd +!else +crt = -MD +!endif +!else +!if $(DEBUG) +crt = -MTd +!else +crt = -MT +!endif +!endif + +INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" +BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) +CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE +TCL_CFLAGS = -DUSE_TCL_STUBS -DVERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) $(OPTDEFINES) + +#--------------------------------------------------------------------- +# Link flags +#--------------------------------------------------------------------- + +!if $(DEBUG) +ldebug = -debug:full -debugtype:cv +!else +ldebug = -release -opt:ref -opt:icf,3 +!endif + +### Declarations common to all linker options +lflags = -nologo -machine:$(MACHINE) $(ldebug) + +!if $(PROFILE) +lflags = $(lflags) -profile +!endif + +!if $(ALIGN98_HACK) && !$(STATIC_BUILD) +### Align sections for PE size savings. +lflags = $(lflags) -opt:nowin98 +!else if !$(ALIGN98_HACK) && $(STATIC_BUILD) +### Align sections for speed in loading by choosing the virtual page size. +lflags = $(lflags) -align:4096 +!endif + +!if $(LOIMPACT) +lflags = $(lflags) -ws:aggressive +!endif + +dlllflags = $(lflags) -dll +conlflags = $(lflags) -subsystem:console +guilflags = $(lflags) -subsystem:windows +baselibs = $(TCLSTUBLIB) wsock32.lib + +#--------------------------------------------------------------------- +# TclTest flags +#--------------------------------------------------------------------- + +!IF "$(TESTPAT)" != "" +TESTFLAGS = -file $(TESTPAT) +!ENDIF + +#--------------------------------------------------------------------- +# Project specific targets (EDIT) +#--------------------------------------------------------------------- + +all: setup $(PROJECT) +$(PROJECT): setup $(PRJLIB) +install: install-binaries install-libraries install-docs + + +test: setup $(PROJECT) + set TCL_LIBRARY=$(ROOT)/library +!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" + $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) +!else + @echo Please wait while the tests are collected... + $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) > tests.log + type tests.log | more +!endif + +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) @<< +$** +<< + -@del $*.exp + +$(PRJSTUBLIB): $(PRJSTUBOBJS) + $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) + +#--------------------------------------------------------------------- +# Implicit rules +#--------------------------------------------------------------------- + +{$(WINDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(WINDIR)}.rc{$(TMP_DIR)}.res: + $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ +!if $(DEBUG) + -d DEBUG \ +!endif +!if $(TCL_THREADS) + -d TCL_THREADS \ +!endif +!if $(STATIC_BUILD) + -d STATIC_BUILD \ +!endif + $< + +.SUFFIXES: +.SUFFIXES:.c .rc + +#--------------------------------------------------------------------- +# Installation. (EDIT) +# +# You may need to modify this section to reflect the final distribution +# of your files and possibly to generate documentation. +# +#--------------------------------------------------------------------- + +install-binaries: + @echo Installing to '$(SCRIPT_INSTALL_DIR)' + @if not exist $(SCRIPT_INSTALL_DIR)\nul mkdir $(SCRIPT_INSTALL_DIR) + $(CPY) $(PRJLIB) $(SCRIPT_INSTALL_DIR) + +install-libraries: + @echo Installing to '$(SCRIPT_INSTALL_DIR)' + @if exist $(LIBDIR)\nul $(CPY) $(LIBDIR)\*.tcl $(SCRIPT_INSTALL_DIR) + @cd $(SCRIPT_INSTALL_DIR) + @echo pkg_mkIndex -verbose . | $(TCLSH) + +install-docs: + +#--------------------------------------------------------------------- +# Clean up +#--------------------------------------------------------------------- + +clean: + @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) + +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 diff --git a/win/nmakehlp.c b/win/nmakehlp.c new file mode 100644 index 0000000..30f81bf --- /dev/null +++ b/win/nmakehlp.c @@ -0,0 +1,355 @@ +/* ---------------------------------------------------------------------------- + * 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 + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id$ + * ---------------------------------------------------------------------------- + */ +#include +#include +#pragma comment (lib, "user32.lib") +#pragma comment (lib, "kernel32.lib") + +/* 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); + +/* globals */ +typedef struct { + HANDLE pipe; + char buffer[1000]; +} pipeinfo; + +pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; +pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; + + + +/* exitcodes: 0 == no, 1 == yes, 2 == error */ +int +main (int argc, char *argv[]) +{ + char msg[300]; + DWORD dwWritten; + int chars; + + if (argc > 1 && *argv[1] == '-') { + switch (*(argv[1]+1)) { + case 'c': + if (argc != 3) { + chars = wsprintf(msg, "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); + return 2; + } + return CheckForCompilerFeature(argv[2]); + case 'l': + if (argc != 3) { + chars = wsprintf(msg, "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); + return 2; + } + return CheckForLinkerFeature(argv[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); + return 2; + } else if (argc == 3) { + /* if the string is blank, there is no match */ + return 0; + } else { + return IsIn(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.", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + return 0; + } + return GetVersionFromHeader(argv[2], argv[3]); + } + } + chars = wsprintf(msg, "usage: %s -c|-l|-f ...\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) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[100]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + /* 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); + + /* 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"); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &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); + + 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); + return 2; + } + + /* 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. */ + 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. */ + 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. */ + 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); +} + +int +CheckForLinkerFeature (const char *option) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[100]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + /* 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); + + /* 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"); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &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); + + 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); + return 2; + } + + /* 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. */ + 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. */ + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + + /* 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); +} + +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); + 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) +{ + 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); + 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; +} diff --git a/win/rules.vc b/win/rules.vc new file mode 100644 index 0000000..cd24027 --- /dev/null +++ b/win/rules.vc @@ -0,0 +1,432 @@ +#------------------------------------------------------------------------------ +# 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$ +#------------------------------------------------------------------------------ + +!ifndef _RULES_VC +_RULES_VC = 1 + +cc32 = $(CC) # built-in default. +link32 = link +lib32 = lib +rc32 = $(RC) # built-in default. + +!ifndef INSTALLDIR +### Assume the normal default. +_INSTALLDIR = C:\Program Files\Tcl +!else +### Fix the path seperators. +_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 +!if ![ver | find "4.0" > nul] +CPY = echo y | xcopy /i +!else +CPY = xcopy /i /y +!endif +!else +CPY = xcopy /i +RMDIR = deltree /Y +!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] +!endif +!endif + +#---------------------------------------------------------- +# Test for compiler features +#---------------------------------------------------------- + +### test for optimizations +!if [nmakehlp -c -Otip] +!message *** Compiler has 'Optimizations' +OPTIMIZING = 1 +!else +!message *** Compiler doesn't have 'Optimizations' +OPTIMIZING = 0 +!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 +!endif + +!if "$(MACHINE)" == "IA64" +### test for Itanium errata +!if [nmakehlp -c -QIA64_Bx] +!message *** Compiler has 'B-stepping errata workarounds' +ITAN_B_ERRATA = 1 +!else +!message *** Compiler doesn't have 'B-stepping errata workarounds' +ITAN_B_ERRATA = 0 +!endif +!else +ITAN_B_ERRATA = 0 +!endif + +#---------------------------------------------------------- +# Decode the options requested. +#---------------------------------------------------------- + +!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] +STATIC_BUILD = 0 +TCL_THREADS = 0 +DEBUG = 0 +PROFILE = 0 +MSVCRT = 0 +LOIMPACT = 0 +TCL_USE_STATIC_PACKAGES = 0 +USE_THREAD_ALLOC = 0 +!else +!if [nmakehlp -f $(OPTS) "static"] +!message *** Doing static +STATIC_BUILD = 1 +!else +STATIC_BUILD = 0 +!endif +!if [nmakehlp -f $(OPTS) "msvcrt"] +!message *** Doing msvcrt +MSVCRT = 1 +!else +MSVCRT = 0 +!endif +!if [nmakehlp -f $(OPTS) "staticpkg"] +!message *** Doing staticpkg +TCL_USE_STATIC_PACKAGES = 1 +!else +TCL_USE_STATIC_PACKAGES = 0 +!endif +!if [nmakehlp -f $(OPTS) "threads"] +!message *** Doing threads +TCL_THREADS = 1 +!else +TCL_THREADS = 0 +!endif +!if [nmakehlp -f $(OPTS) "symbols"] +!message *** Doing symbols +DEBUG = 1 +!else +DEBUG = 0 +!endif +!if [nmakehlp -f $(OPTS) "profile"] +!message *** Doing profile +PROFILE = 1 +!else +PROFILE = 0 +!endif +!if [nmakehlp -f $(OPTS) "loimpact"] +!message *** Doing loimpact +LOIMPACT = 1 +!else +LOIMPACT = 0 +!endif +!if [nmakehlp -f $(OPTS) "thrdalloc"] +!message *** Doing thrdalloc +USE_THREAD_ALLOC = 1 +!else +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 + + +#---------------------------------------------------------- +# Figure-out how to name our intermediate and output directories. +# We wouldn't want different builds to use the same .obj files +# by accident. +#---------------------------------------------------------- + +SUFX = tsgx + +!if $(DEBUG) +BUILDDIRTOP = Debug +DBGX = g +!else +BUILDDIRTOP = Release +DBGX = +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=) +SUFX = $(SUFX:x=) +!endif +!endif + +!if !$(TCL_THREADS) +TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) +SUFX = $(SUFX:t=) +!endif + +!ifndef TMP_DIR +TMP_DIR = $(TMP_DIRFULL) +!ifndef OUT_DIR +OUT_DIR = .\$(BUILDDIRTOP) +!endif +!else +!ifndef OUT_DIR +OUT_DIR = $(TMP_DIR) +!endif +!endif + + +#---------------------------------------------------------- +# Decode the statistics requested. +#---------------------------------------------------------- + +!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] +TCL_MEM_DEBUG = 0 +TCL_COMPILE_DEBUG = 0 +!else +!if [nmakehlp -f $(STATS) "memdbg"] +!message *** Doing memdbg +TCL_MEM_DEBUG = 1 +!else +TCL_MEM_DEBUG = 0 +!endif +!if [nmakehlp -f $(STATS) "compdbg"] +!message *** Doing compdbg +TCL_COMPILE_DEBUG = 1 +!else +TCL_COMPILE_DEBUG = 0 +!endif +!endif + + +#---------------------------------------------------------- +# Set our defines now armed with our options. +#---------------------------------------------------------- + +OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) + +!if $(TCL_MEM_DEBUG) +OPTDEFINES = -DTCL_MEM_DEBUG +!endif +!if $(TCL_COMPILE_DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS +!endif +!if $(TCL_THREADS) +OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 +!if $(USE_THREAD_ALLOC) +OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 +!endif +!endif +!if $(STATIC_BUILD) +OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD +!endif + +!if $(DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DEBUG +!elseif $(OPTIMIZING) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED +!endif +!if $(PROFILE) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED +!endif +!if "$(MACHINE)" == "IA64" +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT +!endif + + +#---------------------------------------------------------- +# Get common info used when building extensions. +#---------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" + +!if !defined(TCLDIR) +!if exist("$(_INSTALLDIR)\include\tcl.h") +TCLINSTALL = 1 +_TCLDIR = $(_INSTALLDIR) +_TCL_H = $(_INSTALLDIR)\include\tcl.h +TCLDIR = $(_INSTALLDIR) +!else +MSG=^ +Failed to find tcl.h. Set the TCLDIR macro. +!error $(MSG) +!endif +!else +_TCLDIR = $(TCLDIR:/=\) +!if exist("$(_TCLDIR)\include\tcl.h") +TCLINSTALL = 1 +!elseif exist("$(_TCLDIR)\generic\tcl.h") +TCLINSTALL = 0 +!else +MSG =^ +Failed to find tcl.h. The TCLDIR macro does not appear correct. +!error $(MSG) +!endif +_TCL_H = $(_TCLDIR)\generic\tcl.h +!endif + +!if [nmakehlp -v $(_TCL_H) ""] == 0 +!include version.vc +!else +TCL_DOTVERSION = 8.5 +TCL_VERSION = $(TCL_DOTVERSION:.=) +!endif + +!if $(TCLINSTALL) +TCLSH = "$(_INSTALLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" +TCLSTUBLIB = "$(_INSTALLDIR)\lib\tclstub$(TCL_VERSION).lib" +TCLIMPLIB = "$(_INSTALLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" +TCL_LIBRARY = $(_INSTALLDIR)\lib +TCLREGLIB = "$(_INSTALLDIR)\lib\tclreg11$(SUFX:t=).lib" +TCLDDELIB = "$(_INSTALLDIR)\lib\tcldde12$(SUFX:t=).lib" +COFFBASE = \must\have\tcl\sources\to\build\this\target +TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target +TCL_INCLUDES = -I"$(_INSTALLDIR)\include" +!else +TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" +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)\tclreg11$(SUFX:t=).lib" +TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde12$(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. +#---------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" + +!if !defined(TKDIR) +!if exist("$(_INSTALLDIR)\include\tk.h") +TKINSTALL = 1 +_TKDIR = $(_INSTALLDIR) +_TK_H = $(_INSTALLDIR)\include\tk.h +TKDIR = $(_INSTALLDIR) +!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 +!elseif exist("$(_TKDIR)\generic\tk.h") +TKINSTALL = 0 +!else +MSG =^ +Failed to find tk.h. The TKDIR macro does not appear correct. +!error $(MSG) +!endif +_TK_H = $(_TKDIR)\generic\tk.h +!endif + +!if [nmakehlp -v $(_TCL_H) $(_TK_H)] == 0 +!include version.vc +!else +TK_DOTVERSION = 8.5 +TK_VERSION = $(TK_DOTVERSION:.=) +!endif + +!if $(TKINSTALL) +WISH = "$(_INSTALLDIR)\bin\wish$(TK_VERSION)$(SUFX).exe" +TKSTUBLIB = "$(_INSTALLDIR)\lib\tkstub$(TK_VERSION).lib" +TKIMPLIB = "$(_INSTALLDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" +TK_INCLUDES = -I"$(_INSTALLDIR)\include" +!else +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 + + + +#---------------------------------------------------------- +# 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)' + +!endif