'Compile 강좌'에 해당되는 글 4건

  1. 2010.06.26 라이브러리
  2. 2010.06.22 [컴파일 강좌] 2강 - C++ 분할 컴파일
  3. 2010.06.21 [컴파일 강좌] 1강 - C 분할 컴파일
  4. 2010.05.30 컴파일러 옵션

라이브러리

|

입력을 받는 함수 3개( scanf(), getch(), gets() ),
출력을 하는 함수 3개( printf(), putch(), puts() )를 만들었다.
또한 수학 관련 함수 5개를 만들었다.
그리고 네트워크 관련 함수 4개도 만들었다.
이것을 각각 컴파일하여 15개의 오브젝트 파일을 만들어 놓았다.
그리고 헤더 파일도 15개 만들어 놓았다.

이제 main() 함수에서 #include로 필요한 함수의 헤더 파일을 포함시켜주고 그 함수를 사용하면 된다.
그리고 컴파일할 때 main() 함수에서 사용한 함수들의 오브젝트 파일을 포함시켜 컴파일해 주면 된다.
그런데 사용한 함수가 15개라면 아래와 같이 해야 할 것이다.
$ gcc -o main.c scanf.o getch.o gets.o printf.o putch.o puts.o ...
쓸 만하다. 
하지만 사용한 함수가 100개라면 어떻게 할 것인가?

그래서 라이브러리 개념을 도입한다.
잘 아는 단어이다. '도서관'이라는 뜻인데 이것이 컴파일과 무슨 관련이 있다는 것인가?
도서관에는 많은 책들이 있다. 그런데 이 많은 책들이 마구 섞여 있지 않고 잘 분류되어 있다는 것이다.
주제에 맞게 책을 분류하고 분류기호를 정해 놓았기 때문에 이 기호를 보고 원하는 책을 빨리 찾을 수 있다.

자, 다시 컴파일로 돌아오자.
15개의 함수를 입출력, 수학, 네트워크 이렇게 3개로 분류하면 좋을 것 같다.
그리고 각각을 libio, libmath, libnet라고 이름을 붙이자. (반드시 앞에 lib를 붙여주어야 함)
그래서 scanf() 함수를 찾으려면 libio를 찾아가면 되는 것이다.

이제 직접 라이브러리를 만들어보자.
GCC에서는 ar이라는 명령어로 라이브러리를 만들 수 있다.
우리는 3개로 분류하였으므로
libio.a
libmath.a
libnet.a
라는 3개의 파일이 만들어진다.
libio.a는 6개의 입출력 오브젝트 파일을 포함하고 있다.
나머지 파일도 해당 오브젝트 파일을 포함하고 있다.

이제 이 라이브러리 파일을 이용해서 컴파일을 하면 된다.
$ gcc -o main main.c -lio lmath lnet -L.
-l 뒤에 lib와 .a를 뺀 io, math, net를 써주면 된다.
-L 뒤에 라이브러리 파일이 포함된 경로를 포함시켜 준다. main.c와 같은 경로라면 .만 찍어 준다.



$ vi input.c
#include <stdio.h>

int input()
{
int in;
printf("What is your favorite number: ");
scanf("%d", &in);
return in;
}
:wq

$ vi output.c
#include <stdio.h>

void output(int out)
{
printf("Your favorite number is %d.\n", out);
}
:wq

$ vi main.c
#include <stdio.h>

int main()
{
int num;
num = input();
output(num);
return 0;
}
:wq

$ vi input.h
extern int input();
:wq

$vi output.h
extern void output(int)
:wq

$ ls
input.c  input.h  main.c  output.c  output.h
$ gcc -c input.c output.c
$ ls
input.c  input.h  input.o  main.c  output.c  output.h  output.o

$ ar r libmylib.a input.o output.o
ar: creating libmylib.a
$ ls
input.c  input.h  input.o  libmylib.a  main.c  output.c  output.h  output.o

$ ar s libmylib.a
$ ls
input.c  input.h  input.o  libmylib.a  main.c  output.c  output.h  output.o

$ ar t libmylib.a
input.o
output.o
$ ls
input.c  input.h  input.o  libmylib.a  main.c  output.c  output.h  output.o

$ gcc -o main main.c -lmylib -L.
$ ls
input.c  input.h  input.o  libmylib.a  main  main.c  output.c  output.h  output.o

$ ./main
What is your favorite number: 3
Your favorite number is 3.






'Compile 강좌' 카테고리의 다른 글

[컴파일 강좌] 2강 - C++ 분할 컴파일  (0) 2010.06.22
[컴파일 강좌] 1강 - C 분할 컴파일  (0) 2010.06.21
컴파일러 옵션  (0) 2010.05.30
And

[컴파일 강좌] 2강 - C++ 분할 컴파일

|
클래스 헤더 파일
Point.h
클래스 구현 파일
Point.cpp
메인 함수 파일
main.cpp

클래스 구현 파일을 반드시 클래스 헤더 파일을 포함해야 한다.

클래스 헤더 파일에서 cout을 사용하였다면 반드시
#include <iostream>
using namespace std;
를 써 주어야 한다.

클래스 구현 파일에서 cout을 사용하였다면 반드시
#include <iostream>
using namespace std;
를 써 주어야 한다.

메인 함수 파일에서 cout을 사용하였다면 반드시
#include <iostream>
using namespace std;
를 써 주어야 한다.

클래스 헤더 파일과 구현 파일, 메인 함수 파일 모두에서 cout을 사용하였다면 클래스 헤더 파일에만
#include <iostream>
using namespace std;
를 써 주면 된다.
왜냐하면 클래스 구현 파일과 메인 함수 파일이 클래스 헤더 파일을 #include하고 있기 때문이다.

1) 오브젝트 파일 생성 (컴파일 - 어셈블리)
cl /c main.cpp Point.cpp
main.cpp와 Point.cpp 파일을 각각 컴파일한다. 즉,
cl /c main.cpp의 결과로 main.obj 생성
cl / Point.cpp의 결과로 Point.obj 생성

2) 실행 파일 생성 (링크)
cl main.obj Point.obj
이번에는 두 개의 obj 파일을 합쳐 하나의 실행 파일로 만든다.
제일 앞에 있는 obj 파일의 이름이 실행 파일의 이름이 된다.
따라서 main.exe 파일이 생성된다.

cl Point.obj main.obj
제일 앞에 있는 obj 파일의 이름이 실행 파일의 이름이 된다.
따라서 Point.exe 파일이 생성된다.

'-o test'을 쓰면 main.exe와 test.exe 2개의 실행 파일이 생성된다.








'Compile 강좌' 카테고리의 다른 글

라이브러리  (0) 2010.06.26
[컴파일 강좌] 1강 - C 분할 컴파일  (0) 2010.06.21
컴파일러 옵션  (0) 2010.05.30
And

[컴파일 강좌] 1강 - C 분할 컴파일

|
컴파일 강좌
1강 - C 분할 컴파일
2강 - C++ 분할 컴파일
3강 - 정적 라이브러리
4강 - 동적 라이브러리

하나의 파일에 모든 소스 코드를 넣으면 그 파일의 크기는 얼마나 될까? 그리고 여러 사람이 동시에 작업하는 것이 가능할까?
몇 백명이 투입되는 대형 프로젝트의 경우 모든 작업이 분업화되어 작은 부분을 하나하나 합쳐서 커다란 하나의 프로그램을 만든다.

그러면 각각의 파일을 컴파일하여 오브젝트 파일을 생성하고 이 오브젝트 파일을 하나로 합치는 방법에 대해서 알아보자.

예제1) main.c 파일에 모든 함수를 작성한 경우

main1.c
#include <stdio.h>

void swap(int* a, int* b)
{
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}

void disp(int a, int b)
{
    printf("a = %d, b = %d\n", a, b);
}

int main()
{
    int a = 10;
    int b = 30;

    disp(a, b);

    swap(&a, &b);

    disp(a, b);

    return 0;
}
$ gcc -o main1 main1.c


예제2) 3개의 파일로 분할한 경우

swap.c
void swap(int* a, int* b)
{
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}

disp.c
void disp(int a, int b)
{
    printf("a = %d, b = %d\n", a, b);
}

main2.c
#include <stdio.h>
#include "swap.c"
#include "disp.c"

int main()
{
    int a = 10;
    int b = 30;

    disp(a, b);

    swap(&a, &b);

    disp(a, b);

    return 0;
}
$ gcc -o main2 main2.c

main2.c는 #include문에 의해 swap.c의 소스와 disp.c의 소스가 그대로 옮겨지기 때문에 전처리가 완료된 후의 소스코드는 main1.c와 같아진다.
소스파일만 분할되어 있고 main2.c만 컴파일한 것이므로 분할 컴파일이라 할 수 없다.


예제3) 3개의 파일을 각각 컴파일하여 오브젝트 파일을 생성한 후, 하나의 실행파일을 만드는 경우

swap.c
void swap(int* a, int* b)
{
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}
$ gcc -c swap.c

disp.c
#include <stdio.h>

void disp(int a, int b)
{
    printf("a = %d, b = %d\n", a, b);
}
$ gcc -c disp.c

main3.c
void swap(int*, int*);
void disp(int, int);

int main()
{
    int a = 10;
    int b = 30;

    disp(a, b);

    swap(&a, &b);

    disp(a, b);

    return 0;
}
$ gcc -c main3 main3.c

main() 함수에 있던 #include문이 다 없어졌다.
일단 아래의 두 줄은 각각의 파일을 따로 컴파일하였으므로 당연히 필요가 없다.
대신 main() 함수 안에서 쓰이는 두 함수의 원형을 선언해 주었다.

다음으로 #include <stdio.h>에 대해 살펴 보자.
main1.c나 main2.c에서는 disp() 함수에서 printf() 함수가 쓰이고 있다.
그래서 #include <stdio.h>를 써주었으나 이번에는 각각의 파일을 따로 컴파일하는 것이므로 printf() 함수가 쓰이고 있는 disp.c에 #include <stdio.h>를 써주어야 한다.
그리고 main3.c에서는 #include <stdio.h>를 지웠다.

각각의 파일을 컴파일하면 3개의 오브젝트 파일이 생성된다.
그러면 최종적으로 3개의 파일을 합쳐 보자.
$ gcc -o main3 swap.o disp.o main3.o


하나의 프로그램을 만드는데 100명이 투입되었다고 해 보자.
1명당 함수를 10개씩 만들어야 한다.
그러면 main.c 파일에 선언되어야 하는 함수의 원형은 몇 개일까? 1000개이다.
main.c를 만드는 사람은 1000개의 함수 원형을 선언해야 한다.
그런데 #include문을 생각해 보자.
#include문은 해당 파일의 내용을 그대로 붙여 넣어 준다.
그러면 각각의 개발자가 자신이 만든 함수의 원형 10개만 따로 파일로 작성해서 main.c를 만드는 사람에게 넘겨주면 되는 것 아니겠는가?
main.c를 만드는 사람은 100개의 파일을 받아서 그 파일들만 #include문으로 추가해 주면 된다.
그러면 나머지 900라인을 쓸 필요가 없어지는 것이다. 이 파일이 바로 .h로 끝나는 헤더파일이다.
물론 헤더 파일이 필요한 이유가 이것 때문만은 아니다.

예제4) 헤더 파일을 활용하여 각각의 파일을 컴파일하는 경우

swap.c와 disp.c는 예제3과 동일하다.

swap.h
void swap(int* a, int* b);

disp.h
void disp(int a, int b);

main4.c
#include "swap.h"
#include "disp.h"

int main()
{
    int a = 10;
    int b = 30;

    disp(a, b);

    swap(&a, &b);

    disp(a, b);

    return 0;
}

swap.h와 disp.h에서 각각의 함수의 원형을 선언해 주고, main4.c에서 선언되어 있던 함수의 원형을 지우고 두 개의 헤더파일을 포함시켰다.
결국 전처리가 끝나면 main3.c와 같아진다.
하지만 각각의 헤더 파일에 함수가 10개씩 들어 있다면 main3.c의 경우는 20줄을 적어야 했으나 main4.c는 2줄만 적어주면 된다.

'Compile 강좌' 카테고리의 다른 글

라이브러리  (0) 2010.06.26
[컴파일 강좌] 2강 - C++ 분할 컴파일  (0) 2010.06.22
컴파일러 옵션  (0) 2010.05.30
And

컴파일러 옵션

|
http://fussion.egloos.com/9674149 동적라이브러리 설명 상세히

MS Visual Studio Compiler

명령어 : cl
>cl test.c
>dir
test.c
test.exe


옵션 :

/P : Preprocessing 후 .i 파일만 생성
>cl /P test.c
>dir
test.c
test.i


/Fa : Compiling 후 .asm 파일, .obj 파일, .exe 파일 생성
>cl /Fa test.c
>dir
test.asm
test.c
test.exe
test.obj


/c : Assembling 후 .obj 파일만 생성
>cl /c test.c
>dir
test.c
test.obj


GCC (GNU Compiler Colletion)

명령어 : gcc
$ gcc test.c
$ ls
a.out  test.c


옵션 :

-E -o 파일명 : Preprocessing 후 .i 파일만 생성 (-o 파일명을 하지 않으면 전처리 내용을 화면에 출력함)
$ gcc -E -o test.i test.c
$ ls
test.c  test.i


-S : Compiling 후 .s 파일만 생성
$ gcc -S test.c
$ ls
test.c  test.s


-c : Assembling 후 .o 파일만 생성
$ gcc -c test.c
$ ls
test.c  test.o


그 외 옵션 :

--save-temps : .i, .s, .o, 실행 파일을 모두 생성

-g : Debugging 정보까지 포함시켜 컴파일

-l : Library 파일이름을 지정 (소문자 엘)

-L : Library가 위치한 디렉토리를 지정

-Wall : 모든 경고 메시지 출력



GCC는 GNU Compiler Collection 의 준 말이지요.  전에는 C Compiler 였으나, C++이나 자바, 포트란 등을 모두 컴파일 할 수 있을 정도로 커져서 컴파일러 콜렉션이라고 바뀌었습니다.

 

GCC는 컴파일러입니다.  컴파일러의 패스를 보면 쉽게 쉽게 이해 됩니다.

 

전처리기 -> 컴파일러 -> 어셈블러 -> 링커

 

이 과정으로 되는 것을 GCC 하나로 모두 진행 시켜서 소스 파일을 실행 파일로 생성 시켜 줍니다.

 

전처리기는 cpp(C pre processor) 이며, 소스 파일의 주석 제거 및 define을 치환하는 기능 등을 합니다.

그다음은 cc 이며, C Compiler 입니다.  이것은 전처리기를 거친 소스 파일을 어셈 파일로 변환합니다.

그다음은 as 이며, assmeber 입니다.  이것은 에셈파일을 오브젝트 파일로 변환해주십니다.

마지막으로 ld 이며, linker 입니다.  이것은 오브젝트 파일들을 묶어서 실행 파일로 변환해 줍니다.

 

GCC는 옵션이 아주 많이 있지만, 자주 쓰이는 옵션은 제한 되어 있습니다.

 

--help : 간단한 옵션을 출력해줍니다.

--version : gcc의 버젼을 출력해 줍니다.

 

-o : 출력 파일명을 지정할 때 사용합니다.

-c : 링킹 과정을 진행 하지 않고 .o 파일인 오브젝트 파일까지만 생성 하게 됩니다.

-S : 어셈블러까지 진행 하지 않고, 컴파일러까지의 출력은 .S 어셈블러 파일을 생성하게 됩니다.

-O1 ~ -O3 : 최적화 수준을 지정합니다. 숫자가 클수록 높은 수준의 최적화를 하게 됩니다.

-g : 디버깅을 위한 정보를 컴파일 하면서 생성하게 됩니다.

-D : define 을 할수 있는 옵션입니다.

-l (엘) : 라이브러리 이름을 지정합니다.

 -L : 추가 라이브러리 디렉토리를 지정합니다.

-W : 모든 에러 메시지 출력

-w : 모든 에러 메시지를 출력 하지 않음

-I(아이) : 추가 헤더 파일이 있는 디렉토리를 지정합니다.


많이 사용되는 옵션을 축약했습니다.
외의 자세한 사항은 매뉴얼 명령어를 참고하시면 됩니다.
터미널을 여신 후 입력창에  'man gcc'를 입력합니다.

'Compile 강좌' 카테고리의 다른 글

라이브러리  (0) 2010.06.26
[컴파일 강좌] 2강 - C++ 분할 컴파일  (0) 2010.06.22
[컴파일 강좌] 1강 - C 분할 컴파일  (0) 2010.06.21
And
prev | 1 | next