nmakehlp.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:12k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * ----------------------------------------------------------------------------
  3.  * nmakehlp.c --
  4.  *
  5.  * This is used to fix limitations within nmake and the environment.
  6.  *
  7.  * Copyright (c) 2002 by David Gravereaux.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * ----------------------------------------------------------------------------
  13.  * RCS: @(#) $Id: nmakehlp.c,v 1.1.6.5 2006/10/18 08:56:21 patthoyts Exp $
  14.  * ----------------------------------------------------------------------------
  15.  */
  16. #define _CRT_SECURE_NO_DEPRECATE
  17. #include <windows.h>
  18. #pragma comment (lib, "user32.lib")
  19. #pragma comment (lib, "kernel32.lib")
  20. #include <stdio.h>
  21. #include <math.h>
  22. #if defined(_M_IA64) || defined(_M_AMD64)
  23. #pragma comment(lib, "bufferoverflowU")
  24. #endif
  25. /* ISO hack for dumb VC++ */
  26. #ifdef _MSC_VER
  27. #define   snprintf _snprintf
  28. #endif
  29. /* protos */
  30. int CheckForCompilerFeature(const char *option);
  31. int CheckForLinkerFeature(const char *option);
  32. int IsIn(const char *string, const char *substring);
  33. int GrepForDefine(const char *file, const char *string);
  34. DWORD WINAPI ReadFromPipe(LPVOID args);
  35. /* globals */
  36. #define CHUNK 25
  37. #define STATICBUFFERSIZE    1000
  38. typedef struct {
  39.     HANDLE pipe;
  40.     char buffer[STATICBUFFERSIZE];
  41. } pipeinfo;
  42. pipeinfo Out = {INVALID_HANDLE_VALUE, ''};
  43. pipeinfo Err = {INVALID_HANDLE_VALUE, ''};
  44. /*
  45.  * exitcodes: 0 == no, 1 == yes, 2 == error
  46.  */
  47. int
  48. main(
  49.     int argc,
  50.     char *argv[])
  51. {
  52.     char msg[300];
  53.     DWORD dwWritten;
  54.     int chars;
  55.     /*
  56.      * Make sure children (cl.exe and link.exe) are kept quiet.
  57.      */
  58.     SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  59.     /*
  60.      * Make sure the compiler and linker aren't effected by the outside world.
  61.      */
  62.     SetEnvironmentVariable("CL", "");
  63.     SetEnvironmentVariable("LINK", "");
  64.     if (argc > 1 && *argv[1] == '-') {
  65. switch (*(argv[1]+1)) {
  66. case 'c':
  67.     if (argc != 3) {
  68. chars = snprintf(msg, sizeof(msg) - 1,
  69.         "usage: %s -c <compiler option>n"
  70. "Tests for whether cl.exe supports an optionn"
  71. "exitcodes: 0 == no, 1 == yes, 2 == errorn", argv[0]);
  72. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  73. &dwWritten, NULL);
  74. return 2;
  75.     }
  76.     return CheckForCompilerFeature(argv[2]);
  77. case 'l':
  78.     if (argc != 3) {
  79. chars = snprintf(msg, sizeof(msg) - 1,
  80.         "usage: %s -l <linker option>n"
  81. "Tests for whether link.exe supports an optionn"
  82. "exitcodes: 0 == no, 1 == yes, 2 == errorn", argv[0]);
  83. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  84. &dwWritten, NULL);
  85. return 2;
  86.     }
  87.     return CheckForLinkerFeature(argv[2]);
  88. case 'f':
  89.     if (argc == 2) {
  90. chars = snprintf(msg, sizeof(msg) - 1,
  91. "usage: %s -f <string> <substring>n"
  92. "Find a substring within anothern"
  93. "exitcodes: 0 == no, 1 == yes, 2 == errorn", argv[0]);
  94. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  95. &dwWritten, NULL);
  96. return 2;
  97.     } else if (argc == 3) {
  98. /*
  99.  * If the string is blank, there is no match.
  100.  */
  101. return 0;
  102.     } else {
  103. return IsIn(argv[2], argv[3]);
  104.     }
  105. case 'g':
  106.     if (argc == 2) {
  107. chars = snprintf(msg, sizeof(msg) - 1,
  108. "usage: %s -g <file> <string>n"
  109. "grep for a #definen"
  110. "exitcodes: integer of the found string (no decimals)n",
  111. argv[0]);
  112. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  113. &dwWritten, NULL);
  114. return 2;
  115.     }
  116.     return GrepForDefine(argv[2], argv[3]);
  117. }
  118.     }
  119.     chars = snprintf(msg, sizeof(msg) - 1,
  120.     "usage: %s -c|-l|-f ...n"
  121.     "This is a little helper app to equalize shell differences between WinNT andn"
  122.     "Win9x and get nmake.exe to accomplish its job.n",
  123.     argv[0]);
  124.     WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
  125.     return 2;
  126. }
  127. int
  128. CheckForCompilerFeature(
  129.     const char *option)
  130. {
  131.     STARTUPINFO si;
  132.     PROCESS_INFORMATION pi;
  133.     SECURITY_ATTRIBUTES sa;
  134.     DWORD threadID;
  135.     char msg[300];
  136.     BOOL ok;
  137.     HANDLE hProcess, h, pipeThreads[2];
  138.     char cmdline[100];
  139.     hProcess = GetCurrentProcess();
  140.     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  141.     ZeroMemory(&si, sizeof(STARTUPINFO));
  142.     si.cb = sizeof(STARTUPINFO);
  143.     si.dwFlags   = STARTF_USESTDHANDLES;
  144.     si.hStdInput = INVALID_HANDLE_VALUE;
  145.     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
  146.     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  147.     sa.lpSecurityDescriptor = NULL;
  148.     sa.bInheritHandle = FALSE;
  149.     /*
  150.      * Create a non-inheritible pipe.
  151.      */
  152.     CreatePipe(&Out.pipe, &h, &sa, 0);
  153.     /*
  154.      * Dupe the write side, make it inheritible, and close the original.
  155.      */
  156.     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
  157.     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  158.     /*
  159.      * Same as above, but for the error side.
  160.      */
  161.     CreatePipe(&Err.pipe, &h, &sa, 0);
  162.     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
  163.     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  164.     /*
  165.      * Base command line.
  166.      */
  167.     lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X ");
  168.     /*
  169.      * Append our option for testing
  170.      */
  171.     lstrcat(cmdline, option);
  172.     /*
  173.      * Filename to compile, which exists, but is nothing and empty.
  174.      */
  175.     lstrcat(cmdline, " .\nul");
  176.     ok = CreateProcess(
  177.     NULL,     /* Module name. */
  178.     cmdline,     /* Command line. */
  179.     NULL,     /* Process handle not inheritable. */
  180.     NULL,     /* Thread handle not inheritable. */
  181.     TRUE,     /* yes, inherit handles. */
  182.     DETACHED_PROCESS, /* No console for you. */
  183.     NULL,     /* Use parent's environment block. */
  184.     NULL,     /* Use parent's starting directory. */
  185.     &si,     /* Pointer to STARTUPINFO structure. */
  186.     &pi);     /* Pointer to PROCESS_INFORMATION structure. */
  187.     if (!ok) {
  188. DWORD err = GetLastError();
  189. int chars = snprintf(msg, sizeof(msg) - 1,
  190. "Tried to launch: "%s", but got error [%u]: ", cmdline, err);
  191. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
  192. FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
  193. (300-chars), 0);
  194. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
  195. return 2;
  196.     }
  197.     /*
  198.      * Close our references to the write handles that have now been inherited.
  199.      */
  200.     CloseHandle(si.hStdOutput);
  201.     CloseHandle(si.hStdError);
  202.     WaitForInputIdle(pi.hProcess, 5000);
  203.     CloseHandle(pi.hThread);
  204.     /*
  205.      * Start the pipe reader threads.
  206.      */
  207.     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
  208.     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
  209.     /*
  210.      * Block waiting for the process to end.
  211.      */
  212.     WaitForSingleObject(pi.hProcess, INFINITE);
  213.     CloseHandle(pi.hProcess);
  214.     /*
  215.      * Wait for our pipe to get done reading, should it be a little slow.
  216.      */
  217.     WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
  218.     CloseHandle(pipeThreads[0]);
  219.     CloseHandle(pipeThreads[1]);
  220.     /*
  221.      * Look for the commandline warning code in both streams.
  222.      *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
  223.      */
  224.     return !(strstr(Out.buffer, "D4002") != NULL
  225.              || strstr(Err.buffer, "D4002") != NULL
  226.              || strstr(Out.buffer, "D9002") != NULL
  227.              || strstr(Err.buffer, "D9002") != NULL);
  228. }
  229. int
  230. CheckForLinkerFeature(
  231.     const char *option)
  232. {
  233.     STARTUPINFO si;
  234.     PROCESS_INFORMATION pi;
  235.     SECURITY_ATTRIBUTES sa;
  236.     DWORD threadID;
  237.     char msg[300];
  238.     BOOL ok;
  239.     HANDLE hProcess, h, pipeThreads[2];
  240.     char cmdline[100];
  241.     hProcess = GetCurrentProcess();
  242.     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  243.     ZeroMemory(&si, sizeof(STARTUPINFO));
  244.     si.cb = sizeof(STARTUPINFO);
  245.     si.dwFlags   = STARTF_USESTDHANDLES;
  246.     si.hStdInput = INVALID_HANDLE_VALUE;
  247.     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
  248.     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  249.     sa.lpSecurityDescriptor = NULL;
  250.     sa.bInheritHandle = TRUE;
  251.     /*
  252.      * Create a non-inheritible pipe.
  253.      */
  254.     CreatePipe(&Out.pipe, &h, &sa, 0);
  255.     /*
  256.      * Dupe the write side, make it inheritible, and close the original.
  257.      */
  258.     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
  259.     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  260.     /*
  261.      * Same as above, but for the error side.
  262.      */
  263.     CreatePipe(&Err.pipe, &h, &sa, 0);
  264.     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
  265.     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  266.     /*
  267.      * Base command line.
  268.      */
  269.     lstrcpy(cmdline, "link.exe -nologo ");
  270.     /*
  271.      * Append our option for testing.
  272.      */
  273.     lstrcat(cmdline, option);
  274.     ok = CreateProcess(
  275.     NULL,     /* Module name. */
  276.     cmdline,     /* Command line. */
  277.     NULL,     /* Process handle not inheritable. */
  278.     NULL,     /* Thread handle not inheritable. */
  279.     TRUE,     /* yes, inherit handles. */
  280.     DETACHED_PROCESS, /* No console for you. */
  281.     NULL,     /* Use parent's environment block. */
  282.     NULL,     /* Use parent's starting directory. */
  283.     &si,     /* Pointer to STARTUPINFO structure. */
  284.     &pi);     /* Pointer to PROCESS_INFORMATION structure. */
  285.     if (!ok) {
  286. DWORD err = GetLastError();
  287. int chars = snprintf(msg, sizeof(msg) - 1,
  288. "Tried to launch: "%s", but got error [%u]: ", cmdline, err);
  289. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
  290. FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
  291. (300-chars), 0);
  292. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
  293. return 2;
  294.     }
  295.     /*
  296.      * Close our references to the write handles that have now been inherited.
  297.      */
  298.     CloseHandle(si.hStdOutput);
  299.     CloseHandle(si.hStdError);
  300.     WaitForInputIdle(pi.hProcess, 5000);
  301.     CloseHandle(pi.hThread);
  302.     /*
  303.      * Start the pipe reader threads.
  304.      */
  305.     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
  306.     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
  307.     /*
  308.      * Block waiting for the process to end.
  309.      */
  310.     WaitForSingleObject(pi.hProcess, INFINITE);
  311.     CloseHandle(pi.hProcess);
  312.     /*
  313.      * Wait for our pipe to get done reading, should it be a little slow.
  314.      */
  315.     WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
  316.     CloseHandle(pipeThreads[0]);
  317.     CloseHandle(pipeThreads[1]);
  318.     /*
  319.      * Look for the commandline warning code in the stderr stream.
  320.      */
  321.     return !(strstr(Out.buffer, "LNK1117") != NULL ||
  322.              strstr(Err.buffer, "LNK1117") != NULL ||
  323.              strstr(Out.buffer, "LNK4044") != NULL ||
  324.              strstr(Err.buffer, "LNK4044") != NULL);
  325. }
  326. DWORD WINAPI
  327. ReadFromPipe(
  328.     LPVOID args)
  329. {
  330.     pipeinfo *pi = (pipeinfo *) args;
  331.     char *lastBuf = pi->buffer;
  332.     DWORD dwRead;
  333.     BOOL ok;
  334.   again:
  335.     if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
  336. CloseHandle(pi->pipe);
  337. return (DWORD)-1;
  338.     }
  339.     ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
  340.     if (!ok || dwRead == 0) {
  341. CloseHandle(pi->pipe);
  342. return 0;
  343.     }
  344.     lastBuf += dwRead;
  345.     goto again;
  346.     return 0;  /* makes the compiler happy */
  347. }
  348. int
  349. IsIn(
  350.     const char *string,
  351.     const char *substring)
  352. {
  353.     return (strstr(string, substring) != NULL);
  354. }
  355. /*
  356.  * Find a specified #define by name.
  357.  *
  358.  * If the line is '#define TCL_VERSION "8.5"', it returns 85 as the result.
  359.  */
  360. int
  361. GrepForDefine(
  362.     const char *file,
  363.     const char *string)
  364. {
  365.     FILE *f;
  366.     char s1[51], s2[51], s3[51];
  367.     int r = 0;
  368.     double d1;
  369.     f = fopen(file, "rt");
  370.     if (f == NULL) {
  371. return 0;
  372.     }
  373.     do {
  374. r = fscanf(f, "%50s", s1);
  375. if (r == 1 && !strcmp(s1, "#define")) {
  376.     /*
  377.      * Get next two words.
  378.      */
  379.     r = fscanf(f, "%50s %50s", s2, s3);
  380.     if (r != 2) {
  381. continue;
  382.     }
  383.     /*
  384.      * Is the first word what we're looking for?
  385.      */
  386.     if (!strcmp(s2, string)) {
  387. fclose(f);
  388. /*
  389.  * Add 1 past first double quote char. "8.5"
  390.  */
  391. d1 = atof(s3 + 1);   /*    8.5  */
  392. while (floor(d1) != d1) {
  393.     d1 *= 10.0;
  394. }
  395. return ((int) d1);   /*    85   */
  396.     }
  397. }
  398.     } while (!feof(f));
  399.     fclose(f);
  400.     return 0;
  401. }