你要定义一个告诉make如何工作的makefile,类似于一个批命令文件,可语法是make的语法,可以很复杂。

解决方案 »

  1.   

    //抱歉,忘了作者了Wisual C++ Documentation->Using Visual C++->Visual C++User's Guide ->Working with Projects ->Overview NMAKE reference。
    几乎所有的C/C++命令行工具里都有Make工具。Microsoft的叫做NMAKE,Borland的叫做Make。基本的语法都差不多。
    举一个例子:
    你开发一个最简单的Win32 Application.源文件如下:
    //Generic.h
    #ifndef __GENERIC_H
    #define __GENERIC_H#include <windows.h>#define GENERICCLASS "GenericClass"
    #define GENERICWINDOW "Generic Window"LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
    BOOL CALLBACK AboutProc(HWND,UINT,WPARAM,LPARAM);#endif  /*__GENERIC_H*///Generic.C#include <windows.h>
    #include "Generic.h"
    #include "resource.h"int WINAPI WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine,
        int nCmdShow)
    {
        WNDCLASSEX wcex;
        HWND hwnd;
        MSG msg;
        wcex.cbSize=sizeof(wcex);
        wcex.style=0;
        wcex.lpfnWndProc=MainWndProc;
        wcex.cbClsExtra=0;
        wcex.cbWndExtra=0;
        wcex.hInstance=hInstance;
        wcex.hIcon=LoadIcon(NULL,IDI_APPLICATION);
        wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
        wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName=NULL;
        wcex.lpszClassName=GENERICCLASS;
        wcex.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
        if (!RegisterClassEx(&wcex))
        {
            return FALSE;
        }
        hwnd=CreateWindowEx(0,
            GENERICCLASS,
            GENERICWINDOW,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInstance,
            NULL);
        if (!hwnd)
        {
            return FALSE;
        }
        ShowWindow(hwnd,nCmdShow);
        while (GetMessage(&msg,NULL,0,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }LRESULT CALLBACK MainWndProc(HWND hwnd,
                                 UINT message,
                                 WPARAM wp,
                                 LPARAM lp)
    {
        static HINSTANCE hInstance;
        static HMENU hMenu;
        switch (message)
        {
        case WM_CREATE:
        {
            hInstance=((LPCREATESTRUCT)lp)->hInstance;
            hMenu=LoadMenu(hInstance,(LPSTR)IDR_MAINMENU);
            SetMenu(hwnd,hMenu);
        }
            return 0;
        case WM_COMMAND:
        {
            switch (LOWORD(wp))
            {
            case IDM_EXIT:
            {
                char lpszQueryQuit[32];
                char lpszQueryQuitCaption[32];
                LoadString(hInstance,IDS_QUERYQUIT,lpszQueryQuit,32);
                LoadString(hInstance,IDS_QUERYQUITCAPTION,lpszQueryQuitCaption,32);
                if (MessageBox(hwnd,lpszQueryQuit,lpszQueryQuitCaption,MB_YESNO)==IDYES)
                {
                    PostQuitMessage(0);
                }
            }
                return 0;
            case IDM_ABOUT:
            {
                return DialogBoxParam(hInstance,
                    (LPSTR)IDD_ABOUT,
                    hwnd,
                    AboutProc,
                    (LPARAM)hInstance);
            }
                return 0;
            default:
                break;
            }
        }
            return 0;
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc;
            RECT rc;
            char lpszHello[32];
            hdc=BeginPaint(hwnd,&ps);
            GetClientRect(hwnd,&rc);
            LoadString(hInstance,IDS_HELLO,lpszHello,32);
            DrawText(hdc,lpszHello,lstrlen(lpszHello),&rc,DT_CENTER);
            EndPaint(hwnd,&ps);
        }
            return 0;
        case WM_DESTROY:
        {
            PostQuitMessage(0);
        }
            return 0;
        default:
            break;
        }
        return DefWindowProc(hwnd,message,wp,lp);
    }BOOL CALLBACK AboutProc(HWND hwnd,UINT message,WPARAM wp,LPARAM lp)
    {
        static HINSTANCE hInstance;
        switch (message)
        {
        case WM_INITDIALOG:
        {
            hInstance=(HINSTANCE)hInstance;
        }
            return TRUE;
        case WM_COMMAND:
        {
            if ((LOWORD(wp)==IDOK)||(LOWORD(wp)==IDCANCEL))
            {
                EndDialog(hwnd,0);
            }
        }
            return TRUE;
        default:
            break;
        }
        return FALSE;
    }//Generic.rc
    #include "resource.h"
    #include <windows.h>
    /////////////////////////////////////////////////////////////////////////////
    //
    // Dialog
    //IDD_ABOUT DIALOG DISCARDABLE  0, 0, 187, 69
    STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "Generic Dialog"
    FONT 10, "System"
    BEGIN
        DEFPUSHBUTTON  "OK",IDOK,66,43,50,14
        CTEXT          "Generic Window 32 bits Application\nWriter Tian Wei",
                        IDC_STATIC,24,15,136,18
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //IDR_MAINMENU MENU DISCARDABLE 
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "E&xit",                      IDM_EXIT
        END
        POPUP "&Help"
        BEGIN
            MENUITEM "&About",                      IDM_ABOUT
        END
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // String Table
    //STRINGTABLE DISCARDABLE 
    BEGIN
        IDS_QUERYQUIT          "Do you really want to quit?"
        IDS_QUERYQUITCAPTION    "Confirm quitting"
        IDS_HELLO              "Hello world!"
    END//resource.h
    #define IDS_QUERYQUIT                  1
    #define IDS_QUERYQUITCAPTION            2
    #define IDS_HELLO                      3
    #define IDD_ABOUT                      101
    #define IDR_MAINMENU                    102
    #define IDM_EXIT                        40001
    #define IDM_ABOUT                      40002
    #define IDC_STATIC                      -1现在你写一个如下的generic.mak,用于Microsoft的命令行工具。
    //generic.mak
    mspath = d:\progra~1\micros~1\vc98 #这一行应该是你的VC的路径,不一定是我写的。
    linkpath = $(mspath)\bin
    cpath = $(mspath)\bin
    rpath = $(mspath)\bin
    cincpath = $(mspath)\includecc = $(cpath)\cl.exe 
    cflags = -c -I$(cincpath) rincpath = $(cincpath)
    rc = $(rpath)\rc.exe
    rflags = -i$(rincpath) libpath = $(mspath)\lib
    link = $(linkpath)\link.exe
    linkflags = -subsystem:windows -libpath:$(libpath)crtlibs = libc.libwin32libs = kernel32.lib     user32.lib     gdi32.lib     uuid.lib     oldnames.lib     advapi32.lib     comctl32.lib     comdlg32.lib     shell32.lib     shlwapi.lib comlibs = ole32.lib     oleaut32.lib     oledlg.lib deflibs = $(crtlibs) $(win32libs) $(comlibs)all: generic.exegeneric.obj: generic.c generic.h resource.h
        $(cc) $(cflags) generic.cgeneric.res: generic.rc resource.h
        $(rc) $(rflags) generic.rcgeneric.exe: generic.obj generic.res
        $(link) $(linkflags) -out:generic.exe generic.obj generic.res $(deflibs)最后,可以在控制台方式下这样运行NMAKE:
    namke -f"Generic.mak"
    当然,如果nmake的路径不再环境变量里,还要用全名。
    最后就会产生generic.obj,generic.res,generic.exe三个文件。
    如果用VC,那么在选择工程类型的时候要选择makefile,这样的话就可以正确的编译。当然,你会觉得每次写这么复杂的makefile太累了。VC的Include目录里边有一个Win32.mak,里边定义好了编译和连接用到的标志,比如generic.mak可以这么写:!include <win32.mak>all: generic.exegeneric.obj: generic.c generic.h resource.h
        $(cc) $(cdebug) $(cflags) $(cvars) generic.cgeneric.res: generic.rc resource.h
        $(rc) $(cdebug) $(rcvars) -r -fo generic.res generic.rcgeneric.exe
        $(link) $(linkdebug) $(guiflags) -out:generic.exe generic.obj generic.res $(guilibs)简单地说以#开头的是注释,以!开头的是一些控制语句, 比如!if !else !endif  !include等等。以$开头并且用括号包起来的是常量。常量必须先定义。比如cc = cl.exe就把cc定义成了cl.exe以后遇到$(cc)就会被扩展成cl.exe。
    最重要的是依赖性。
    以下
    generic.obj: generic.c generic.h resource.h
        $(cc) $(cdebug) $(cflags) $(cvars) generic.c
    表示generic.obj依赖generic.c generic.h resource.h三个文件。如果其中一个被改动过,那么generic.obj叫要被重新建立。建立的方法是$(cc) $(cdebug) $(cflags) $(cvars) generic.c。
    all: generic.exe表示最终的目标是generic.exe
      

  2.   

    makefile已经有了。vc下此文件是否名为nmake?
      

  3.   

    vc下面也叫makefile。
    nmake.exe是读取makefile并且执行的程序。unix下面
    make是读取makefile并且执行的程序。