2010-06-22 59 views
15

Phần mềm của tôi có một chính để sử dụng bình thường và một phần mềm khác để kiểm tra đơn vị. Tôi chỉ thích nó nếu có một tùy chọn để gcc xác định chức năng "chính" nào cần sử dụng.là có một trình biên dịch GCC/linker tùy chọn để thay đổi tên của chính?

+0

Điều này có thể được thực hiện với một trình biên dịch không? tức là không có "thực hiện thử nghiệm -D; làm sạch sẽ; làm"? Tôi thấy thoải mái khi vận chuyển "cùng một mã" mà tôi đã thử nghiệm. –

+0

Bạn chỉ cần '-D' cho tệp có chứa nguồn điện của bạn. Tôi muốn có một makefile để xây dựng mọi thứ, bao gồm cả tệp chính hai lần (một lần với và một lần không có -D ... lưu ý rằng nó phải được biên dịch với hai tên tệp đầu ra khác nhau). Sau đó liên kết tất cả lại với nhau hai lần: một lần cho việc xây dựng thử nghiệm, một lần cho xây dựng bình thường. – mschaef

Trả lời

8

Đặt chúng trong các tệp riêng biệt và chỉ định một tệp .c để sử dụng bình thường và một tệp .c để thử nghiệm.

Cách khác, #define thử nghiệm trên dòng lệnh sử dụng thử nghiệm xây dựng và sử dụng một cái gì đó như:

int main(int argc, char *argv[]) 
{ 
#ifdef TESTING 
    return TestMain(argc, argv); 
#else 
    return NormalMain(argc, argv); 
#endif 
} 

int TestMain(int argc, char *argv[]) 
{ 
    // Do testing in here 
} 

int NormalMain(int argc, char *argv[]) 
{ 
    //Do normal stuff in here 
} 
+7

Ngoài ra, chỉ cần FYI để OP, chỉ cần thêm '-DTESTING' vào danh sách các đối số để gcc. –

+0

tốt hơn để sử dụng -e cho điểm vào hoặc dải --strip-symbol –

+0

@Alex: "bạn không thể xóa câu trả lời được chấp nhận" :( –

2

Edit: Billy đánh tôi đến câu trả lời, nhưng đây là nhiều hơn một chút nền

trực tiếp hơn, chính thường là một hàm của thư viện chuẩn. Thứ gọi main không phải là C, mà là thư viện chuẩn. Hệ điều hành tải ứng dụng, chuyển quyền kiểm soát đến điểm vào của thư viện (_start trong GCC) và thư viện cuối cùng gọi main. Đây là lý do tại sao điểm vào cho một ứng dụng cửa sổ có thể là WinMain và không phải là thông thường. Lập trình nhúng có thể có cùng một loại điều. Nếu bạn không có một thư viện chuẩn, bạn phải viết điểm vào mà thư viện thường cung cấp (trong số những thứ khác), và bạn có thể đặt tên cho nó bất cứ điều gì bạn muốn.

Trong chuỗi công cụ GCC, bạn cũng có thể thay thế điểm nhập của thư viện bằng cách sử dụng tùy chọn -e. (Đối với vấn đề đó, bạn cũng có thể loại bỏ các thư viện hoàn toàn.)


Hãy riêng của bạn:

int main(int argc, char *argv[]) 
{ 
#if defined(BUILD_UNIT_TESTS) 
    return main_unittest(argc, argv); 
#endif 
#if defined(BUILD_RUNTIME) 
    return main_run(argc, argv); 
#endif 
} 

Nếu bạn không thích ifdef, sau đó viết hai mô-đun chính mà chỉ chứa chính. Liên kết một trong các bài kiểm tra đơn vị và phần còn lại để sử dụng bình thường.

7

Tôi giả định rằng bạn đang sử dụng tính năng Thực hiện hoặc tương tự. Tôi sẽ tạo hai tệp chứa các triển khai khác nhau của hàm chính, sau đó trong makefile, xác định hai mục tiêu riêng biệt có phụ thuộc giống nhau trên các tệp còn lại của bạn, ngoại trừ một tệp sử dụng "main test unit" và "other normal" ". Một cái gì đó như thế này:

normal: main_normal.c file1.c file2.c 
unittest: main_unittest.c file1.c file2.c 

Miễn là mục tiêu "bình thường" ở gần đầu trang makefile hơn thì gõ "make" sẽ chọn theo mặc định. Bạn sẽ phải gõ "make unittest" để xây dựng mục tiêu thử nghiệm của bạn.

+0

xây dựng với tự động –

+4

+1: Tôi rất thích cách tiếp cận này để cố gắng nhồi nhét cả hai đường vào –

0
#ifdef TESTING 

int main() 

{ 

/* testing code here */ 

} 

#else 

int main() 

{ 

/* normal code here */ 

} 

#endif 

$ gcc -DTESTING=1 -o a.out filename.C#building for testing

$ gcc -UTESTING -o a.out filename.C#building for normal purposes

man gcc chỉ cho tôi những -D và -U

+1

Nhược điểm duy nhất của việc này là bạn cần phải có toàn bộ mã của 'main' bên trong' define' ... một số màu cú pháp của một số IDE sẽ có màu xám trên tất cả các mã thử nghiệm (vì nó không được định nghĩa thông thường) có thể trở nên khá khó chịu –

7

Bạn có thể sử dụng macro để đổi tên một chức năng để chính.

#ifdef TESTING 
#define test_main main 
#else 
#define real_main main 
#endif 

int test_main(int argc, char *argv[]) { ... } 
int real_main(int argc, char *argv[]) { ... } 
14

Các câu trả lời khác ở đây khá hợp lý, nhưng nói đúng vấn đề bạn không thực sự là một với GCC, mà đúng hơn là với thời gian chạy C. Bạn có thể chỉ định một điểm vào chương trình của mình bằng cách sử dụng cờ -e để ld.tài liệu của tôi nói:

-e symbol_name

Chỉ định điểm nhập cảnh của một thực thi chính. Theo mặc định tên mục nhập là "bắt đầu" được tìm thấy trong crt1.o chứa mã keo cần thiết lập và gọi chính().

Điều đó có nghĩa bạn có thể ghi đè lên các điểm nhập cảnh nếu bạn thích, nhưng bạn có thể không muốn làm điều đó cho một chương trình C bạn có ý định chạy bình thường trên máy tính của bạn, vì start có thể làm tất cả các loại công cụ hệ điều hành cụ thể đó là bắt buộc trước khi chương trình của bạn chạy. Nếu bạn có thể thực hiện start của riêng mình, bạn có thể làm những gì bạn muốn.

+3

Trên Linux: 1) bạn cũng cần '-nostartfiles' cho GCC, hoặc khác' main' trong 'crt1.o' sẽ không xác định và nó sẽ không liên kết 2) Bạn phải thoát với 'exit()' rõ ràng, nếu không 'return' to nowhere sẽ segfault 3)' argv' sẽ không được thiết lập cho bạn –

0

Bạn thể phải chạy ld riêng để sử dụng chúng, nhưng ld hỗ trợ scripts để xác định nhiều khía cạnh của tập tin đầu ra (bao gồm cả các điểm nhập cảnh).

+0

Nhưng 'main' không phải là mục nhập điểm (ít nhất là trên mo st hệ thống). –

5

tôi có xu hướng sử dụng các file khác nhau và làm cho thử nghiệm và sản xuất xây dựng, nhưng nếu bạn đã có một tập tin với

int test_main (int argc, char*argv[]) 

int prod_main (int argc, char*argv[]) 

sau đó các tùy chọn trình biên dịch để chọn một hoặc người kia là người chính là -Dtest_main=main-Dprod_main=main

+1

Có thể đáng để chỉ ra rằng nếu bạn không thể đổi tên chính trong tệp sản xuất vì lý do nào đó (như đã xảy ra trong trường hợp của tôi), bạn có thể hoán đổi tên biểu tượng trong chuyển đổi -D, nghĩa là làm cho nó '-Dmain = ignore_main' khi biên dịch chính sản xuất. – ttreitlinger

0

Trước hết, bạn không thể có hai chức năng có tên main trong một c ompilation, do đó, hoặc là các nguồn trong các tập tin khác nhau hoặc bạn đang sử dụng biên dịch có điều kiện. Dù bằng cách nào bạn cũng có hai tệp .o khác nhau. Do đó, bạn không cần một liên kết tùy chọn; bạn chỉ cần chuyển tệp .o mà bạn muốn trong một đối số .

Nếu bạn không thích điều đó, bạn có thể làm những điều ưa thích với dlopen() để kéo main từ bất kỳ tệp đối tượng nào mà bạn đặt tên động. Tôi có thể tưởng tượng được những trường hợp có thể hữu ích khi thử nghiệm đơn vị, chỉ cần đặt tất cả vào một thư mục, và mã của bạn đi vào thư mục, lấy từng tệp đối tượng, tải động và chạy thử nghiệm của nó. Nhưng để bắt đầu, một cái gì đó đơn giản hơn có thể được chỉ ra.

0

Nếu bạn sử dụng vào LD "-e symbol_name" (trong đó symbol_name là chức năng chính của bạn, tất nhiên) bạn cũng cần "-nostartfiles" nếu không lỗi của "undefined reference to main" sẽ được tạo.

+3

Tôi không nghĩ rằng điều này sẽ giúp với vấn đề của OP. Việc bỏ qua các tệp khởi động sẽ khiến bạn bị hỏng môi trường trong đó thư viện chuẩn sẽ không hoạt động đúng cách. Tôi nghĩ chỉ là '-Dmain' và tương tự là những gì cần thiết. –

5

Tôi đã có cùng một vấn đề hôm nay: m1.c và m2.c cả hai đều có chức năng chính nhưng cần được liên kết và chạy một trong số chúng. Giải pháp: sử dụng dải để loại bỏ các biểu tượng chính từ một trong số họ sau khi biên dịch nhưng trước khi liên kết:

gcc -c m1.c m2.c; strip --strip-symbol main m1.o; gcc m1.o m2.o; ./a.out 

sẽ chạy chính từ m2

gcc -c m1.c m2.c; strip --strip-symbol main m2.o; gcc m1.o m2.o; ./a.out 

sẽ chạy chính từ m1

Nếu không có dải :

gcc - m1.c m2.c 
m2.o: In function `main': 
m2.c:(.text+0x0): multiple definition of `main' 
m1.o:m1.c:(.text+0x0): first defined here 
collect2: ld returned 1 exit status 
Các vấn đề liên quan