본문 바로가기

Studying/Computer Programs

C언어 라이브러리 만들기

자주 쓰는 함수들을 라이브러리 형태로 만들어 두면, 프로그램을 짤 때 편리합니다. 오브젝트 파일로부터 라이브러리를 제작하고, 이를 헤더 파일과 함께 이용하는 방법을 알아볼텐데요. 만약 이러한 개념들이 낮설게 느껴지거나 C/C++ 프로그램을 빌드하는 과정을 더 자세히 알고 싶으시다면, 시작하기에 앞서서 다음 포스팅을 읽어보시면 큰 도움이 되리라 생각합니다.

 

 

C/C++ 코드가 프로그램이 되는 과정

여기서는 C언어 또는 C++로 작성된 소스 파일, 헤더 파일의 개념과 이들을 빌드하여 하나의 프로그램을 만드는 과정에 대해 간략하게 짚어보겠습니다. 여러 개의 소스, 헤더 파일들로 이루어진

swstar.tistory.com

 

예를 들어서 함수 Function이 mylib.c 라는 소스코드에 정의되어 있고, 프로토타입이 mylib.h 라는 헤더 파일에 다음과 같이 선언되어 있는 경우를 상정해 봅시다.

 

mylib.h

#ifndef MYLIB_H
#define MYLIB_H

double Function(double x);

#endif

 

mylib.c

double Function(double x) {
    double ret;

    // ... 함수의 본체 ...

    return ret;
}

 

[1] 우선 mylib.c 를 컴파일해서 오브젝트 파일을 만듭니다.
  [정적 라이브러리(static library)의 경우] gcc -c mylib.c
  [동적 라이브러리(shared library)의 경우] gcc -fPIC -c mylib.c

 

[2] 오브젝트 파일로부터 라이브러리를 생성합니다.
* 볼드체로 표시된 mylib부분을 적당한 이름으로 바꿔줍니다.
  [정적 라이브러리(static library)의 경우] ar rc libmylib.a mylib.o
  [동적 라이브러리(shared library)의 경우] gcc -shared -o libmylib.so mylib.o

만약 여러 개의 소스 파일로부터 라이브러리를 만드는 경우라면, 라이브러리 파일 이름 뒤에 오브젝트 파일들의 이름을 나열해 줍니다. 예를 들어서 mylib1.c, mylib2.c, mylib3.c 소스 파일들로부터 각각 mylib1.o, mylib2.o, mylib3.o 오브젝트 파일들을 얻었다면, 다음과 같이 합시다.
  [정적 라이브러리] ar rc libmylib.a mylib1.o mylib2.o mylib3.o
  [동적 라이브러리] gcc -shared -o libmylib.so mylib1.o mylib2.o mylib3.o
이 때 헤더 파일은 소스 파일별로 하나씩 만들어도 되고, 모든 소스파일에 정의된 함수들의 프로토타입을 모아서 단일한 헤더 파일을 만들어도 무방합니다.

 

[3] 정적 라이브러리의 경우 libmylib.a 라이브러리 내의 인덱스를 만듭니다.
  ranlib libmylib.a

 

이렇게 만들어진 라이브러리를 다른 프로그램에서 사용할 때는 mylib.h 를 포함시켜 주고, -lmylib 라는 옵션을 통해 링크시켜 주면 됩니다. 예를 들어서 다음과 같은 main.c 소스코드가 있다면,

 

main.c

// ...

#include<mylib.h>

/* ...
 * 전처리기
 * 전역변수
 * 함수 프로토타입 등
 * ... */

int main (int argc, char *argv[]) {

    // ... 메인함수 내용 ...

    double x, y;

    // ... 메인함수 내용 ...

    y = Function(x);

    // ... 메인함수 내용 ...

    return 0;
}

 

다음과 같이 빌드를 해줍니다.

 

  • 컴파일
    gcc main.c -c -I[mylib.h의 위치]
  • 링크
    gcc main.o -L[libmylib.a(so)의 위치] -lmylib -o [실행파일 이름]

 

한 가지 주목할 점은 헤더 파일은 컴파일 과정에서, 그리고 라이브러리 파일은 링크 과정에서 개입한다는 것인데요. 소스 파일로부터 오브젝트 파일을 만드는 컴파일 과정에서는, 헤더 파일에 있는 프로토타입을 통해 함수의 존재를 알려주기만 하면 됩니다. 반면에 실행파일을 만드는 링크 과정에서는 함수의 구체적인 역할을 알려줘야 하는데, 이 때 라이브러리 파일이 들어가게 되는 거죠.


예를 들어서 mylib.h 와 libmylib.a(so) 가 /homes/INCLUDE 와 /homes/LIBRARY 에 각각 저장되어 있다면,
  gcc main.c -c -I/homes/INCLUDE
  gcc main.o -L/homes/LIBRARY -lmylib -o run.exec
라고 해줍니다. 그러면 run.exec 라는 이름의 실행파일이 생성되어 프로그램을 구동할 수 있게 됩니다.

 

터미널 콘솔을 열때 미리 경로를 지정해주면, -I 및 -L 옵션을 생략하는 것이 가능합니다.

 

  • bash shell 의 경우
    홈디렉토리에 있는 .bashrc 파일 (또는 macOS의 경우 .bash_profile 파일)을 열어서
      export C_INCLUDE_PATH=/homes/INCLUDE:$C_INCLUDE_PATH
      export LIBRARY_PATH=/homes/LIBRARY:$LIBRARY_PATH
    를 추가합니다.
  • TC shell 의 경우
    홈디렉토리에 있는 .tcshrc 파일을 열어서
      setenv C_INCLUDE_PATH /homes/INCLUDE:$C_INCLUDE_PATH
      setenv LIBRARY_PATH /homes/LIBRARY:$LIBRARY_PATH
    를 추가합니다.


이렇게 하면, 컴파일러는 /homes/INCLUDE 에 있는 헤더파일과 /homes/LIBRARY 에 있는 라이브러리들을 자동으로 탐색하므로, -I 및 -L 옵션이 필요없죠. 환경변수를 설정하는데 있어서 :$C_INCLUDE_PATH 및 :$LIBRARY_PATH 를 추가하는 이유는 기존의 값들을 유지한 채로 새로운 디렉토리를 추가하기 위함입니다. 콜론 (:) 기호로 분리된 여러 개의 디렉토리를 추가할 수 있는 기능을 이용한 방법입니다.

 

동적 라이브러리를 이용하기 위해서는 LD_LIBRARY_PATH 라는 환경변수를 추가로 지정해줘야 하는데요. 이는 프로그램 실행파일에게 동적 라이브러리 파일의 위치를 알려주는 역할을 합니다. 정적 라이브러리의 경우 실행 파일에 관련정보가 저장되므로 프로그램을 빌드하고 나면 라이브러리 파일이 없어도 실행이 가능한 반면, 동적 라이브러리는 프로그램이 실행되는 시점에 라이브러리의 정보가 필요합니다. 컴파일과 링크에 필요한 LIBRARY_PATH 환경변수와 비슷하게 다음과 같이 설정할 수 있습니다.

 

  • bash shell 의 경우
      export LD_LIBRARY_PATH=/homes/LIBRARY:$LD_LIBRARY_PATH
  • TC shell 의 경우
      setenv LD_LIBRARY_PATH /homes/LIBRARY:$LD_LIBRARY_PATH

 

출처 : https://randu.org/tutorials/c/libraries.php

 

C Programming Tutorial: Creating Libraries

Quick Navigation Bar debugging techniques :: creating libraries :: tips and tricks [ toc | forums ]   Note: If the document URL does not begin with https://randu.org/tutorials/c/ then you are viewing a copy. Please direct your browser to the correct locat

randu.org

 

* 정적 라이브러리와 동적 라이브러리의 차이점

 

Difference between static and shared libraries?

What is the difference between static and shared libraries? I use Eclipse and there are several project types including Static Libraries and Shared Libraries? Does one have an advantage over the o...

stackoverflow.com

 

* LIBRARY_PATH 와 LD_LIBRARY_PATH 의 차이점

 

LD_LIBRARY_PATH vs LIBRARY_PATH

I'm building a simple C++ program and I want to temporarily substitute a system supplied shared library with a more recent version of it, for development and testing. I tried setting the LD_LIBRAR...

stackoverflow.com

 

여기서는 C언어로 라이브러리를 만드는 법에 대해 다루었습니다만, extern "C" 코드블록 및 __cplusplus 식별자를 사용하면 C++ 에서도 사용가능한 범용 헤더파일을 만들 수 있습니다. 본문의 예시에 나온 mylib.h 헤더파일의 경우 다음과 같이 바꿀 수 있습니다.

 

#ifndef MYLIB_H
#define MYLIB_H

#undef __WRAP_CXX_INI
#undef __WRAP_CXX_FIN
#ifdef __cplusplus
  #define __WRAP_CXX_INI extern "C" {
  #define __WRAP_CXX_FIN } 
#else
  #define __WRAP_CXX_INI /* empty */
  #define __WRAP_CXX_FIN /* empty */
#endif

__WRAP_CXX_INI

double Function(double x);

__WRAP_CXX_FIN

#endif

 

이렇게 하면 C언어뿐만 아니라 C++ 프로그램에서도 라이브러리를 사용할 수 있게 되는데요. 이 방법에 대한 자세한 사항은 다음 포스팅을 참고하면 좋습니다.

 

 

C언어와 C++를 조합한 프로그래밍

프로그램을 만들다 보면 C언어로 작성된 함수를 C++ 프로그램에서 사용하거나, 그 반대의 경우가 생길 때가 있습니다. 뿐만 아니라 C언어로 만들어진 라이브러리를 C++ 프로그램에서도 사용할 수

swstar.tistory.com

 

앞에서 헤더 파일과 라이브러리 파일을 자동으로 탐색하는 위치를 설정하기 위해 환경변수들을 사용하는 것에 대해 언급 했었습니다. 여기서는 C/C++ 컴파일러가 사용하는 환경변수를 중심으로 이야기했습니다만, 일반적으로 프로그램은 여러 환경변수의 값들을 조회하고 이용하죠. 환경변수의 개념과 C/C++ 프로그램에서 이를 사용하는 방법에 대한 더 자세한 사항은 다음 포스팅에 소개되어 있습니다.

 

 

환경변수의 개념과 C/C++ 에서의 응용

여기서는 환경변수 (environment variable)의 개념과, 이를 C언어 또는 C++ 프로그램에서 사용하는 방법을 알아봅시다. 프로그램 외부에서 환경변수와 그 값들을 정의하고, 이를 프로그램에서 사용할

swstar.tistory.com

 

마이크로소프트의 통합 개발환경인 비주얼 스튜디오에서도 C언어 및 C++ 라이브러리를 직접 제작하고 사용할 수 있습니다. 자세한 내용이 궁금하시다면, 다음 포스팅이 큰 도움이 되리라 생각합니다.

 

 

비주얼 스튜디오 C/C++ 라이브러리 만들기

이번 포스팅에서는 마이크로소프트 비주얼 스튜디오에서 C언어 또는 C++ 라이브러리를 제작하고 사용하는 법에 대해 알아봅시다. 라이브러리는 정적 (static) 라이브러리와 동적 (dynamic) 라이브러

swstar.tistory.com

 



같이 알고 있으면 좋은 C/C++ 팁들

 

명령행 인자

 

Command-Line Arguments (C/C++ 공통)

C++를 배우기 위해 책을 보는데, command-line arguments에 대한 내용이 있었다. 메인함수를 특별한 방법으로 정의해서, 프로그램을 실행시킬때 커맨드 라인에서 옵션을 지정해줄 수 있다고 한다. int mai

swstar.tistory.com

 

함수를 인자로 사용하기

 

C/C++ 에서 함수를 매개변수로 사용하기

일반적으로 C언어나 C++ 에서 사용하는 함수의 경우, 인자(매개변수) 혹은 파라미터로 변수를 받아갑니다. 이 값들을 가지고 정의된 기능을 수행하게 되죠. 하지만 프로그램을 만들다 보면 함수

swstar.tistory.com

 

포트란과의 하이브리드

 

C/C++와 Fortran을 조합한 프로그래밍

수치계산을 위한 프로그램을 짜다 보면, 포트란 함수를 C 혹은 C++ 에서 쓰거나, 그 반대의 경우가 생길 때가 있습니다. 특히 역사가 좀 오래된 모델을 가져다 쓸 때 그렇죠. C언어에서 함수를 특

swstar.tistory.com

 

동적 메모리 할당 (malloc)

 

C 언어의 malloc 함수

학부때부터 수치계산 할때면 항상 C언어를 써 왔지만, 배열과 포인터의 등가관계에 대해서는 극히 최근에야 알게 되었다. 예를 들어서 1) double a[10]; 을 선언했다면, 배열의 이름 a는 포인터 변수

swstar.tistory.com