如何用文件編譯
① 如何編譯一個 dll文件
創建DLL工程
這里,我們為了簡要說明DLL的原理,我們決定使用最簡單的編譯環境VC6.0,如下圖,我們先建立一個新的Win32 Dynamic-Link Library工程,名稱為「MyDLL」,在Visual Studio中,你也可以通過建立Win32控制台程序,然後在「應用程序類型」中選擇「DLL」選項,
點擊確定,選擇「一個空的DLL工程」,確定,完成即可。
一個簡單的dll
在第一步我們建立的工程中建立一個源碼文件」dllmain.cpp「,在「dllmain.cpp」中,鍵入如下代碼
[cpp] view plain
#include <Windows.h>
#include <stdio.h>
BOOL APIENTRY DllMain(HMODULE hMole, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
之後,我們直接編譯,即可以在Debug文件夾下,找到我們生成的dll文件,「MyDLL.dll」,注意,代碼裡面的printf語句,並不是必須的,只是我們用於測試程序時使用。而DllMain函數,是dll的進入/退出函數。
實際上,讓線程調用DLL的方式有兩種,分別是隱式鏈接和顯式鏈接,其目的均是將DLL的文件映像映射進線程的進程的地址空間。我們這里只大概提一下,不做深入研究,如果感興趣,可以去看《Window高級編程指南》的第12章內容。
隱式鏈接調用
隱士地鏈接是將DLL的文件影響映射到進程的地址空間中最常用的方法。當鏈接一個應用程序時,必須制定要鏈接的一組LIB文件。每個LIB文件中包含了DLL文件允許應用程序(或另一個DLL)調用的函數的列表。當鏈接器看到應用程序調用了某個DLL的LIB文件中給出的函數時,它就在生成的EXE文件映像中加入了信息,指出了包含函數的DLL文件的名稱。當操作系統載入EXE文件時,系統查看EXE文件映像的內容來看要裝入哪些DLL,而後試圖將需要的DLL文件映像映射到進程的地址空間中。當尋找DLL時,系統在系列位置查找文件映像。
1.包含EXE映像文件的目錄
2.進程的當前目錄
3.Windows系統的目錄
4.Windows目錄
5.列在PATH環境變數中的目錄
這種方法,一般都是在程序鏈接時控制,反映在鏈接器的配置上,網上大多數講的各種庫的配置,比如OPENGL或者OPENCV等,都是用的這種方法
顯式鏈接調用
這里我們只提到兩種函數,一種是載入函數
[cpp] view plain
HINSTANCE LoadLibrary(LPCTSTR lpszLibFile);
HINSTANCE LoadLibraryEx(LPCSTR lpszLibFile,HANDLE hFile,DWORD dwFlags);
返回值HINSTANCE值指出了文件映像映射的虛擬內存地址。如果DLL不能被映進程的地址空間,函數就返回NULL。你可以使用類似於
[cpp] view plain
LoadLibrary("MyDLL")
或者
[cpp] view plain
LoadLibrary("MyDLL.dll")
的方式進行調用,不帶後綴和帶後綴在搜索策略上有區別,這里不再詳解。
顯式釋放DLL
在顯式載入DLL後,在任意時刻可以調用FreeLibrary函數來顯式地從進程的地址空間中解除該文件的映像。
[cpp] view plain
BOOL FreeLibrary(HINSTANCE hinstDll);
這里,在同一個進程中調用同一個DLL時,實際上還牽涉到一個計數的問題。這里也不在詳解。
線程可以調用GetMoleHandle函數:
[cpp] view plain
GetMoleHandle(LPCTSTR lpszMoleName);
來判斷一個DLL是否被映射進進程的地址空間。例如,下面的代碼判斷MyDLL.dll是否已被映射到進程的地址空間,如果沒有,則裝入它:
[cpp] view plain
HINSTANCE hinstDll;
hinstDll = GetMoleHandle("MyDLL");
if (hinstDll == NULL){
hinstDll = LoadLibrary("MyDLL");
}
實際上,還有一些函數,比如 GetMoleFileName用來獲取DLL的全路徑名稱,FreeLibraryAndExitThread來減少DLL的使用計數並退出線程。具體內容還是參見《Window高級編程指南》的第12章內容,此文中不適合講太多的內容以至於讀者不能一下子接受。
DLL的進入與退出函數
說到這里,實際上只是講了幾個常用的函數,這一個小節才是重點。
在上面,我們看到的MyDLL的例子中,有一個DllMain函數,這就是所謂的進入/退出函數。系統在不同的時候調用此函數。這些調用主要提供信息,常常被DLL用來執行進程級或線程級的初始化和清理工作。如果你的DLL不需要這些通知,就不必再你的DLL源代碼中實現此函數,例如,如果你創建的DLL只含有資源,就不必實現該函數。但如果有,則必須像我們上面的格式。
DllMain函數中的ul_reason_for_call參數指出了為什麼調用該函數。該參數有4個可能值: DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH、DLL_PROCESS_DETACH。
其中,DLL_PROCESS_ATTACH是在一個DLL首次被映射到進程的地址空間時,系統調用它的DllMain函數,傳遞的ul_reason_for_call參數為DLL_PROCESS_ATTACH。這只有在首次映射時發生。如果一個線程後來為已經映射進來的DLL調用LoadLibrary或LoadLibraryEx,操作系統只會增加DLL的計數,它不會再用DLL_PROCESS_ATTACH調用DLL的DllMain函數。
而DLL_PROCESS_DETACH是在DLL被從進程的地址空間解除映射時,系統調用它的DllMain函數,傳遞的ul_reason_for_call值為DLL_PROCESS_DETACH。我們需要注意的是,當用DLL_PROCESS_ATTACH調用DLL的DllMain函數時,如果返回FALSE,說明初始化不成功,系統仍會用DLL_PROCESS_DETACH調用DLL的DllMain。因此,必須確保沒有清理那些沒有成功初始化的東西。
DLL_THREAD_ATTACH:當進程中創建一個線程時,系統察看當前映射到進程的地址空間中的所有DLL文件映像,並用值DLL_THREAD_ATTACH調用所有的這些DLL的DllMain函數。該通知告訴所有的DLL去執行線程級的初始化。注意,當映射一個新的DLL時,進程中已有的幾個線程在運行,系統不會為已經運行的線程用值DLL_THREAD_ATTACH調用DLL的DllMain函數。
而DLL_THREAD_DETACH,如果線程調用ExitThread來終結(如果讓線程函數返回而不是調用ExitThread,系統會自動調用ExitThread),系統察看當前映射到進程空間的所有DLL文件映像,並用值DLL_THREAD_DETACH來調用所有的DLL的DllMain函數。該通知告訴所有的DLL去執行線程級的清理工作。
這里,我們需要注意的是,如果線程的終結是因為系統中的一個線程調用了TerminateThread,系統就不會再使用DLL_THREAD_DETACH來調用DLL和DllMain函數。這與TerminateProcess一樣,不再萬不得已時,不要使用。
下面,我們貼出《Window高級編程指南》中的兩個圖來說明上述四種參數的調用情況。
好的,介紹了以上的情況,下面,我們來繼續實踐,這次,建立一個新的空的win32控制台工程TestDLL,不再多說,代碼如下:
[cpp] view plain
#include <iostream>
#include <Windows.h>
using namespace std;
DWORD WINAPI someFunction(LPVOID lpParam)
{
cout << "enter someFunction!" << endl;
Sleep(1000);
cout << "This is someFunction!" << endl;
Sleep(1000);
cout << "exit someFunction!" << endl;
return 0;
}
int main()
{
HINSTANCE hinstance = LoadLibrary("MyDLL");
if(hinstance!=NULL)
{
cout << "Load successfully!" << endl;
}else {
cout << "Load failed" << endl;
}
HANDLE hThread;
DWORD dwThreadId;
cout << "createThread before " << endl;
hThread = CreateThread(NULL,0,someFunction,NULL,0,&dwThreadId);
cout << "createThread after " << endl;
cout << endl;
Sleep(3000);
cout << "waitForSingleObject before " << endl;
WaitForSingleObject(hThread,INFINITE);
cout << "WaitForSingleObject after " << endl;
cout << endl;
FreeLibrary(hinstance);
return 0;
}
代碼很好理解,但是前提是,你必須對線程有一定的概念。另外,注意,我們上面編譯的獲得的「MyDLL.dll"必須拷貝到能夠讓我們這個工程找到的地方,也就是上面我們提到的搜索路徑中的一個地方。
這里,我們先貼結果,當然,這只是在我機器上其中某次運行結果。
有了上面我們介紹的知識,這個就不是很難理解,主進程在調用LoadLibrary時,用DLL_PROCESS_ATTACH調用了DllMain函數,而線程創建時,用DLL_THREAD_ATTACH調用了DllMain函數,而由於主線程和子線程並行的原因,可能輸出的時候會有打斷。但是,這樣反而能讓我們更清楚的理解程序。
② 文件夾下的源文件如何編譯
1.DOS界面先轉換到D盤下的操作:開始-運行-cmd-D:
2.利用cd命令進入代碼所在的文件夾:cd 1
3.編譯代碼:javac 類名.java(後綴名不是.class而櫻橘滲已.java)
4.運行代碼: java 類伍明名(運行不需要脊脊加後綴名)
附:在DOS界面 輸入java -version 檢查一下JDK 並注意 環境變數的配置
③ c多個文件如何編譯
關於整個 C 語言中的主函數 main( ) 如何調用相關的頭文件(*.h)、以及調用其它獨立的模塊(*.c)的方法,關鍵在於對於如何編寫 makefile 文件的真正理解、以及真正掌握編寫規則。
由於我已經有很多年沒有編寫過 C 語言源程序、以及編寫 makefile 文件了,但是可以大概給你提供一個思路就是:
下面的文本文件假設以 my_makefile 為例,編譯環境為 linux 系統,C 語言編譯器為 gcc。
但是在這里注意一點:我的 my_makefile 文件中的注釋語句是否是分號進行注釋,我已經不太記得了,這個需要自己再參考一下。
另外就是:對源文件(*.c)、以及生成可執行文件(my_runfile)在 my_makefile 文件中的前後次序,我也記不清了,僅供參考。
myprog1.o: myprog1.c ; myprog1.o 的生成依賴於 myprog1.c 這個源程序
gcc -c myprog1.c ; 使用 Linux 系統的 C 語言編譯器對 myprog1.c 只編譯、不鏈接
myprog2.o: myprog2.c ; myprog2.o 的生成依賴於 myprog2.c 這個源程序
gcc -c myprog2.c ;使用 Linux 系統的 C 語言編譯器對 myprog2.c 只編譯、不鏈接
my_runfile: myprog1.o myprog2.o ; 可執行文件 my_runfile 的生成依賴於 myprog1.o、myprog2.o 這兩個目標文件
gcc -o my_runfile myprog1.o myprog2.o ; 使用 cc 的 -o 選項生成用戶自定義的可執行文件:my_runfile,如果不指定 -o 選項,cc 編譯器生成的預設可執行文件名為:a.out
運行命令為:
$make -f my_makefile (使用 -f 選項代替預設的 make 文件名 makefile)
④ windows怎麼編譯.c文件
(1)先用記事本編寫如下所示的代碼,並另存為hello.cpp,假設其保存路徑為
C:\Users\Administrator\Desktop。
#include<iostream>
using namespace std;
int main()
{
cout<<"hello world!"<<endl;
return 0;
}
(2)用記事本寫一段簡單的批處理文件,內容如下所示,在保存文件時選擇另存為,文件名
假設為batch.bat,bat是批處理文件的後綴,保存類型選擇:所有文件(這個尤其需要注意),
假設其保存路徑也是:C:\Users\Administrator\Desktop。
set path=D:\Softwares\en_Visual_Studio2010_Professional_x86_x16-81637\VC\bin
set include=D:\Softwares\en_Visual_Studio2010_Professional_x86_x16-81637\VC\include
set lib=D:\Softwares\en_Visual_Studio2010_Professional_x86_x16-81637\VC\lib
上面批處理文件的第一句話表示設置環境變數,這個也可以通過:計算機/屬性/高級系統設置/
環境變數/用戶變數,把D:\Softwares\en_Visual_Studio2010_Professional_x86_x16-81637\VC\bin
放到path的值里去,記得與之前已有值之間用";"隔開。這個path文件夾是我們裝載VS2010時自
帶的,在設置路徑時要根據自己的安裝路徑進行修改,裡麵包含微軟在Windows下給我們提供的
C/C++編譯器cl.exe程序(編譯器自身也是一個軟體程序,只是它的作用是用來編譯其它的程序),
當然還有link.exe鏈接程序,調用cl時,系統會自動調用link程序(後面將看到我們只用了cl命令就
可以進行C/C++程序的編譯、鏈接)。後面兩句話分別表示包含C++中自帶的頭文件庫和靜態鏈接
庫,靜態理解庫包含了頭文件中函數對應的實現部分,為了不讓人們看到其中的源代碼,它以二進
制文件形式編碼,若要查看其內容需要進行反匯編。
(3)通過cmd命令進入DOS操作界面,輸入cd C:\Users\Administrator\Desktop進入cpp文件和bat
批處理文件所在的位置,然後鍵入batch.bat進行批處理,這些操作在VS2010集成開發環境中都為我
設置好了,所以我們在裡面寫C/C++程序時並沒有這樣設置路徑的繁瑣操作,但是通過自己手動的
路徑設置,我們會對程序的編譯、鏈接、執行有更加深入的認識。
(4)鍵入cl hello.cpp,我們會看到計算機報出了「無法啟動此程序,因為計算機中丟失mspdb100.dll。
嘗試重新安裝該程序以解決此問題」的系統儲物,dll文件是動態鏈接庫文件,其是在cl.exe程序運行時
才被載入進來的文件,這個靜態鏈接庫lib文件不同。這說明在D:\Softwares\en_Visual_Studio2010_
Professional_x86_x16-81637\VC\bin路徑里沒有找到mspdb100.dll,原來此文件在文件夾D:\Softwares\
en_Visual_Studio2010_Professional_x86_x16-81637\VC\Common7\IDE里,我們可以將此文件拷到bin
文件夾里,或將D:\Softwares\en_Visual_Studio2010_Professional_x86_x16-81637\Common7\IDE加到
批處理的path環境變數里,或者將其加到cpp文件所在的文件夾里,這只會引起在搜索順序上的不同。
(5)再次鍵入cl hello.cpp,我們看到在C:\Users\Administrator\Desktop文件夾里得到了hello.obj文件,
這是編譯後的輸出文件,但是沒有得到可執行exe文件,DOS界面里出現這樣的錯誤「LINK:fatal error LNK
1104:cannot open file 'kernel32.lib' 「這樣的鏈接錯誤,kernel32.lib是Windows系統文件,通過Windows
自帶的搜索工具,我們看到此文件在文件夾C:\Program Files\Microsoft SDKs\Windows\v7.0A\Lib里,我們
可以將其加到cpp文件所在的文件夾或bin文件里。再次鍵入cl hello.cpp,我們發現這次程序被成功編譯鏈接
了,cpp文件所在的文件夾里多了兩個文件:hello.obj和hello.exe。
(6)在DOS界面鍵入hello.exe,程序被執行,輸出了我們預想的hello world!,至此,在Windows下模擬
linux命令行操作,編譯C/C++文件全部完成了。
⑤ 如何用vs和makefile文件進行編譯
運行cmd.exe (or command.com in win9x)->進到vc/bin目錄->運行vc-vars32.bat->進到makefile 所在的目錄->nmake /f makefile
從sourceforge上下載下來的libjpeg源代碼中有一個makefile.vc的文件,可以通過nmake /f makefile.vc [nodebug=1]來編譯libjpeg,但是只能編譯靜態庫,如果需要編譯dll以便在emacs等程序中使用的話,需要修改makefile.vc和jmorecfg.h文件。在makefile.vc文件中添加編譯dll規則:
以下內容為程序代碼:
libjpeg.lib: $(LIBOBJECTS) $(RM) libjpeg.lib lib -out:libjpeg.lib $(LIBOBJECTS) #
添加以下這行 libjpeg.dll: $(LIBOBJECTS) $(RM) libjpeg.dll link -dll -out:libjpeg.dll $(LIBOBJECTS) 在jmorecfg.h中添加#define _WIN32_#define JPEG_DLL 然後nmake /f makefile.vc nodebug=1就可以編譯了。
將makefile復制為一個.mak文件,然後用VC打開即可!
.mak 就是一個makefile
可以指定怎樣編譯(命令行,必須先設置VC命令行環境)
vcvars32.bat可設置環境,在vc98/bin下 nmake /f XXXX.mak
如果有一個makefile就只要nmake就可以了。
⑥ 如何編譯單個java文件
javac 用於編譯Java文件,格式為:
java [options] [sourcefiles] [@files]
其中:
options:命令行選項;
sourcefiles:一個或多個要編譯的源文件;
@files:一個或多個對源文件進行列表的文件,有時候要編譯的文件很多,一個個敲命令會顯得很長,也不方便修改,可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對多個文件進行編譯,對編譯一個工程很有用,方便,省事。
有幾個比較重要的選項:
-d 用於指定編譯成的class文件的存放位置,預設情況下不指定class文件的存放目錄,編譯的class文件將和源文件在同一目錄下;
-classpath 可以簡寫成-cp,用於搜索編譯所需的class文件,指出編譯所用到的class文件的位置,如jar、zip或者其他包含class文件的目錄,指定該選項會覆蓋CLASSPATH的設定;
-sourcepath用於搜索編譯所需的源文件(即java文件),指定要搜索的源文件的位置,如jar、zip或其他包含java文件的目錄;
需要注意windows下和linux下文件路徑分隔符和文件列表(即-classpath和-sourcepath指定的文件)分隔符的區別:
windows下文件路徑分隔符用 \ ,文件列表分隔符用分號 ;
linux下文件路徑分隔符用 / ,文件列表分隔符用冒號 :
⑦ 如何使用批處理文件進行編譯、鏈接和運行
@echo
cd /d "c:\32masm"
ml /c /coff example.asm
ping -n 5 127.0.1>nul
link /substem:console /entry:start /out:example.exe example.obj io.obj kernel32.lib
ping -n 5 127.0.1>nul
example.exe
保存為.bat,看看是否可以運行.因為我不了解你這個匯編的編譯過程和具體情況,無法肯定可以運行
⑧ 如何使用CMD編譯java文件
1、用記事本編寫java文件,放在某個盤的文件夾下。假設在f:Demo。2、用windoes+R鍵打開cmd窗口,在命令行中輸入f:,目的是將路徑改為java文件所在的路徑。3、在再命令行中輸入cd
文件名(在這里是Demo)
打回車,路徑就到了f:Demo下。4、然後再命令行中輸入javac
java名.java
形成位元組碼文件。5、再輸入java
java文件名就ok了。此時就會將你需要輸出地東西輸出在屏幕上。
⑨ 怎麼用gcc編譯文件
在終端中輸入 gcc 文件名 -o 目標文件名x0dx0a然後 ./目標文件名 就行了,沒有目標文件名,自動存為 ax0dx0a執行 ./a 就行了。x0dx0ax0dx0a在使用Gcc編譯器的時候,我們必須給出一系列必要的調用參數和文件名稱。GCC編譯器的調用參數大約有100多個,其中多數參數我們可能根本就用不到,這里只介紹其中最基本、最常用的參數。x0dx0aGCC最基本的用法是∶gcc [options] [filenames]x0dx0a其中options就是編譯器所需要的參數,filenames給出相關的文件名稱。x0dx0a-c,只編譯,不連接成為可執行文件,編譯器只是由輸入的.c等源代碼文件生成.o為後綴的目標文件,通常用於編譯不包含主程序的子程序文件。x0dx0a-o output_filename,確定輸出文件的名稱為output_filename,同時這個名稱不能和源文件同名。如果不給出這個選項,gcc就給出預設的可執行文件a.out。x0dx0a-g,產生符號調試工具(GNU的gdb)所必要的符號資訊,要想對源代碼進行調試,我們就必須加入這個選項。x0dx0a-O,對程序進行優化編譯、連接,採用這個選項,整個源代碼會在編譯、連接過程中進行優化處理,這樣產生的可執行文件的執行效率可以提高,但是,編譯、連接的速度就相應地要慢一些。x0dx0a-O2,比-O更好的優化編譯、連接,當然整個編譯、連接過程會更慢。x0dx0a-Idirname,將dirname所指出的目錄加入到程序頭文件目錄列表中,是在預編譯過程中使用的參數。C程序中的頭文件包含兩種情況∶x0dx0aA)#include
⑩ 如何編譯C文件
編譯C文件用GCC。
編譯C文件常用方法:
單個文件:
g++
file.cpp
這是最簡單形式,預設輸出為a.out,可以用-o命令指定輸出文件,比如g++
file.cpp
f.out
多個文件:
g++
-c
1.cpp
-o
1.o
g++
-c
2.cpp
-o
2.o
g++
1.o
2.o
-o
prog.out
鏈接成可執行文件:
一般用g++
-o
file
file.cpp
多個文件是g++
-o
file
file1.cpp
file2.cpp
...
編譯C++不是用GCC而是G++.
如果用GCC能編譯但不能鏈接.
多個文件:
1.編譯多個文件,但不連接:
g++
file1.cpp
file2.cpp
會生成兩個文件:file1.o,
file2.o
2.連接:
g++
-o
outFileName
file1.o
file2.o
會生成一個可執行文件:outFileName。
如果想,一步就完成編譯和連接,那麼:
g++
-o
outFileName
file1.cpp
file2.cpp
-o選項控制是否連接。