Ver3.0 ๐ C์ธ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ๊ณผ ์ ์ ยท๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ ๊ด๋ฆฌ

๐ C์ธ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ๊ณผ ์ ์ ยท๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ ๊ด๋ฆฌ
์ฝ๋ ์ฌ์ฌ์ฉ์ ๋ง๋ฒ์ฌ๊ฐ ๋์ด๋ณด์! ๐ฉโจ
์๋ , ์น๊ตฌ! ๐ ์ค๋์ C์ธ์ด๋ก ํ๋ก๊ทธ๋๋ฐํ ๋ ์ ๋ง ์ค์ํ ์ฃผ์ ๋ฅผ ๋ค๋ค๋ณผ ๊ฑฐ์ผ. ๋ฐ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์ด์ง! ํน์ ๊ฐ์ ์ฝ๋๋ฅผ ์ฌ๋ฌ ํ๋ก์ ํธ์์ ๋ณต์ฌ-๋ถ์ฌ๋ฃ๊ธฐ ํ๋๋ผ ์ง์น ์ ์์ด? ์๋๋ฉด ํ์๋ค๊ณผ ์ฝ๋๋ฅผ ๊ณต์ ํ ๋ ํค๋ ํ์ผ ํ๋ํ๋ ๋ณด๋ด๋ ๊ฒ ๊ท์ฐฎ์๋ ์ ์? ๊ทธ๋ด ๋ ํ์ํ ๊ฒ ๋ฐ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ! ๐ฏ
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฝ๊ฒ ๋งํด์ ์์ฃผ ์ฐ๋ ํจ์๋ค์ ๋ชจ์๋์ ์ฝ๋ ์ฐฝ๊ณ ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ. ๋ง์น ๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ํ์ํ ๋๋ง๋ค ๊บผ๋ด ์ธ ์ ์๋ ๊ฑฐ์ง. ๊ทธ๋ฆฌ๊ณ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ํฌ๊ฒ ๋ ๊ฐ์ง ์ข ๋ฅ๊ฐ ์์ด - ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Static Library)์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Dynamic Library). ๊ฐ๊ฐ์ ํน์ง๊ณผ ๋ง๋๋ ๋ฐฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ์ค๋ฌด์์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง ์ฌ๋ฏธ์๊ฒ ์์๋ณด์! ๐
๋จผ์ ๊ธฐ๋ณธ๋ถํฐ ํ์คํ ์ง๊ณ ๋์ด๊ฐ์! ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Library)๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ฝ๋์ ์งํฉ์ด์ผ. C์ธ์ด๋ก ํ๋ก๊ทธ๋๋ฐ์ ํ๋ค ๋ณด๋ฉด ๋น์ทํ ๊ธฐ๋ฅ์ ์ฌ๋ฌ ํ๋ก์ ํธ์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๊ฒ ๋๋๋ฐ, ์ด๊ฑธ ๋งค๋ฒ ์๋ก ์์ฑํ๋ ๊ฑด ๋นํจ์จ์ ์ด์์? ๐ค
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. ๋ค๊ฐ ๋ฌธ์์ด ์ฒ๋ฆฌ ํจ์๋ค์ ๋ง๋ค์๋ค๊ณ ํด๋ณด์. string_trim(), string_split(), string_replace() ๊ฐ์ ํจ์๋ค ๋ง์ด์ผ. ์ด๋ฐ ํจ์๋ค์ ํ๋ก์ ํธ๋ง๋ค ๋ณต์ฌํด์ ์ฐ๋ ๊ฒ๋ณด๋ค, ํ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ง๋ค์ด๋๋ฉด ํจ์ฌ ํธํ๊ฒ ์ง? ๊ฒ๋ค๊ฐ ๋ฒ๊ทธ๋ฅผ ๊ณ ์น๊ฑฐ๋ ๊ธฐ๋ฅ์ ๊ฐ์ ํ ๋๋ ํ ๊ณณ๋ง ์์ ํ๋ฉด ๋๋๊น ๊ด๋ฆฌ๋ ์ฌ์! ๐
๐ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฅ์
1. ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ: ํ ๋ฒ ์์ฑํ ์ฝ๋๋ฅผ ์ฌ๋ฌ ํ๋ก์ ํธ์์ ํ์ฉ
2. ์ ์ง๋ณด์ ์ฉ์ด: ์ค์ ์ง์ค์ ๊ด๋ฆฌ๋ก ๋ฒ๊ทธ ์์ ์ด ๊ฐํธ
3. ๋ชจ๋ํ: ๊ธฐ๋ฅ๋ณ๋ก ๋ถ๋ฆฌํ์ฌ ํ๋ก์ ํธ ๊ตฌ์กฐ๊ฐ ๊น๋ํด์ง
4. ํ์
ํจ์จ: ํ์๋ค๊ณผ ์ฝ๋ ๊ณต์ ๊ฐ ์ฒด๊ณ์ ์ผ๋ก ๊ฐ๋ฅ
5. ์ปดํ์ผ ์๊ฐ ๋จ์ถ: ์ด๋ฏธ ์ปดํ์ผ๋ ์ฝ๋๋ฅผ ๋งํฌ๋ง ํ๋ฉด ๋จ
์ค์ ๋ก ์ฐ๋ฆฌ๊ฐ ํญ์ ์ฐ๋ printf()๋ malloc() ๊ฐ์ ํจ์๋ค๋ ๋ชจ๋ C ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํฌํจ๋ ๊ฑฐ์ผ. ์ด๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์๋ค๋ฉด? ์์๋ง ํด๋ ๋์ฐํ์ง! ๐ฑ ๋ชจ๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ๊ฐ์ ์ ์ถ๋ ฅ ํจ์๋ฅผ ๋ง๋ค์ด์ผ ํ์ ํ ๋๊น.
์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ปดํ์ผ ํ์์ ์คํ ํ์ผ์ ํฌํจ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. Linux/Unix ์์คํ ์์๋ .a (archive) ํ์ฅ์๋ฅผ, Windows์์๋ .lib ํ์ฅ์๋ฅผ ์ฌ์ฉํด. ๐๏ธ
์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฐ์ฅ ํฐ ํน์ง์ ๋ญ๊น? ๋ฐ๋ก ๋งํน(linking) ๋จ๊ณ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฝ๋๊ฐ ์คํ ํ์ผ ์์ผ๋ก ๋ณต์ฌ๋๋ค๋ ๊ฑฐ์ผ. ๋ง์น ์ฑ ์ ๋ณต์ฌํด์ ๋ด ๋ ธํธ์ ๋ถ์ฌ๋ฃ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ. ๊ทธ๋์ ์ต์ข ์คํ ํ์ผ์ ํฌ๊ธฐ๊ฐ ์ปค์ง์ง๋ง, ๋์ ์คํํ ๋ ์ธ๋ถ ํ์ผ์ด ํ์ ์์ด์ ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ ์ ์์ด! ๐
โก ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฅ๋จ์
์ฅ์ :
โข ์คํ ํ์ผ์ด ๋
๋ฆฝ์ ์ด๋ผ ๋ฐฐํฌ๊ฐ ๊ฐ๋จํจ
โข ๋ฐํ์ ์์กด์ฑ์ด ์์ด ์คํ ์๋๊ฐ ๋น ๋ฆ
โข ๋ฒ์ ์ถฉ๋ ๋ฌธ์ ๊ฐ ์์
โข ๋๋ฒ๊น
์ด ์๋์ ์ผ๋ก ์ฌ์
๋จ์ :
โข ์คํ ํ์ผ ํฌ๊ธฐ๊ฐ ์ปค์ง
โข ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์
๋ฐ์ดํธ ์ ์ฌ์ปดํ์ผ ํ์
โข ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ด ๋จ์ด์ง ์ ์์ (์ฌ๋ฌ ํ๋ก๊ทธ๋จ์ด ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋)
์, ์ด์ ์ง์ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ณด์! ๊ฐ๋จํ ์ํ ํจ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ ๋ก ์ฌ์ฉํ ๊ฒ. ๐งฎ
Step 1: ํค๋ ํ์ผ ์์ฑ (mymath.h)
#ifndef MYMATH_H
#define MYMATH_H
// ๋ ์์ ํฉ์ ๋ฐํ
int add(int a, int b);
// ๋ ์์ ์ฐจ๋ฅผ ๋ฐํ
int subtract(int a, int b);
// ๋ ์์ ๊ณฑ์ ๋ฐํ
int multiply(int a, int b);
// ๋ ์์ ๋๋์
๊ฒฐ๊ณผ๋ฅผ ๋ฐํ (0์ผ๋ก ๋๋๊ธฐ ์ฒดํฌ ํฌํจ)
double divide(int a, int b);
// ์ ๊ณฑ ๊ณ์ฐ
int power(int base, int exponent);
#endif // MYMATH_H
ํค๋ ํ์ผ์์ ์ค์ํ ๊ฑด #ifndef, #define, #endif๋ก ๊ฐ์ธ๋ ์ธํด๋ฃจ๋ ๊ฐ๋(include guard)์ผ. ์ด๊ฒ ์์ผ๋ฉด ๊ฐ์ ํค๋ ํ์ผ์ด ์ฌ๋ฌ ๋ฒ ํฌํจ๋ ๋ ์ค๋ณต ์ ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๊ฑฐ๋ ! ๐ก๏ธ
Step 2: ๊ตฌํ ํ์ผ ์์ฑ (mymath.c)
#include "mymath.h"
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
double divide(int a, int b) {
if (b == 0) {
fprintf(stderr, "Error: Division by zero!\n");
return 0.0;
}
return (double)a / b;
}
int power(int base, int exponent) {
int result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
๊ตฌํ ํ์ผ์์๋ ์ค์ ํจ์์ ๋์์ ์ ์ํด. ์ฌ๊ธฐ์ divide() ํจ์์ฒ๋ผ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํฌํจํ๋ ๊ฒ ์ข์ ์ต๊ด์ด์ผ! 0์ผ๋ก ๋๋๋ ์ํฉ์ ์ฒดํฌํ์ง ์์ผ๋ฉด ํ๋ก๊ทธ๋จ์ด ํฌ๋์ ๋ ์ ์๊ฑฐ๋ . ๐ฅ
Step 3: ์ค๋ธ์ ํธ ํ์ผ ์์ฑ
# GCC๋ฅผ ์ฌ์ฉํ ์ปดํ์ผ (์ค๋ธ์ ํธ ํ์ผ ์์ฑ)
gcc -c mymath.c -o mymath.o
# ์ฌ๋ฌ ์์ค ํ์ผ์ด ์๋ค๋ฉด
gcc -c mymath.c -o mymath.o
gcc -c mystring.c -o mystring.o
gcc -c myfile.c -o myfile.o
-c ์ต์ ์ "์ปดํ์ผ๋ง ํ๊ณ ๋งํน์ ํ์ง ๋ง!"๋ผ๋ ์๋ฏธ์ผ. ์ด๋ ๊ฒ ํ๋ฉด .o ํ์ฅ์๋ฅผ ๊ฐ์ง ์ค๋ธ์ ํธ ํ์ผ์ด ์์ฑ๋ผ. ์ด ํ์ผ์ ๊ธฐ๊ณ์ด๋ก ๋ฒ์ญ๋ ์ฝ๋์ง๋ง ์์ง ์คํ ํ์ผ์ ์๋์ผ. ๐ง
Step 4: ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ
# Linux/Unix์์ ar ๋ช
๋ น์ด ์ฌ์ฉ
ar rcs libmymath.a mymath.o
# ์ฌ๋ฌ ์ค๋ธ์ ํธ ํ์ผ์ ํฌํจํ๋ ๊ฒฝ์ฐ
ar rcs libmyutils.a mymath.o mystring.o myfile.o
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด์ฉ ํ์ธ
ar -t libmymath.a
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ธ ์ ๋ณด ํ์ธ
ar -tv libmymath.a
๐ ar ๋ช ๋ น์ด ์ต์ ์ค๋ช
r: ์ค๋ธ์ ํธ ํ์ผ์ ์์นด์ด๋ธ์ ์ถ๊ฐ (์ด๋ฏธ ์์ผ๋ฉด ๊ต์ฒด)
c: ์์นด์ด๋ธ ํ์ผ์ ์๋ก ์์ฑ
s: ์ธ๋ฑ์ค๋ฅผ ์์ฑํ์ฌ ๋งํน ์๋ ํฅ์ (ranlib๊ณผ ๋์ผํ ํจ๊ณผ)
t: ์์นด์ด๋ธ ๋ด์ฉ ๋ชฉ๋ก ์ถ๋ ฅ
v: ์์ธ ์ ๋ณด ์ถ๋ ฅ (verbose mode)
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด๋ฆ์ ๊ด๋ก์ ์ผ๋ก lib๋ก ์์ํด. ๊ทธ๋์ mymath๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ libmymath.a๊ฐ ๋๋ ๊ฑฐ์ง. ๋์ค์ ๋งํนํ ๋๋ -lmymath์ฒ๋ผ lib ์ ๋์ฌ์ .a ํ์ฅ์๋ฅผ ๋นผ๊ณ ์ฌ์ฉํด! ๐
Step 5: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ
// main.c
#include <stdio.h>
#include "mymath.h"
int main() {
int a = 10, b = 5;
printf("Addition: %d + %d = %d\n", a, b, add(a, b));
printf("Subtraction: %d - %d = %d\n", a, b, subtract(a, b));
printf("Multiplication: %d * %d = %d\n", a, b, multiply(a, b));
printf("Division: %d / %d = %.2f\n", a, b, divide(a, b));
printf("Power: %d ^ %d = %d\n", a, 3, power(a, 3));
return 0;
}
# ์ปดํ์ผ ๋ฐ ๋งํน
gcc main.c -L. -lmymath -o myprogram
# ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ ์ง์ ์ง์
gcc main.c libmymath.a -o myprogram
# ์คํ
./myprogram
๐ ์ปดํ์ผ ์ต์ ์ค๋ช
-L. : ํ์ฌ ๋๋ ํ ๋ฆฌ(.)์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐพ์ผ๋ผ๋ ์๋ฏธ
-lmymath : libmymath.a ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋งํฌ
-I/path/to/headers : ํค๋ ํ์ผ ๊ฒ์ ๊ฒฝ๋ก ์ถ๊ฐ
-L/path/to/libs : ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ ๊ฒ์ ๊ฒฝ๋ก ์ถ๊ฐ
๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฌ๋ฆฌ ๋ฐํ์์ ๋ก๋๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. Linux์์๋ .so (Shared Object), Windows์์๋ .dll (Dynamic Link Library) ํ์ฅ์๋ฅผ ์ฌ์ฉํด. ๐
๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํต์ฌ์ ๊ณต์ ์ผ! ์ฌ๋ฌ ํ๋ก๊ทธ๋จ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋ ํ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ณต์ ํด์ ์ฌ์ฉํ ์ ์์ด. ๋ง์น ๋์๊ด ์ฑ ์ฒ๋ผ ์ฌ๋ฌ ์ฌ๋์ด ๊ฐ์ ์ฑ ์ ๋น๋ ค ๋ณผ ์ ์๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ. ์ด๋ ๊ฒ ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ด ํจ์ฌ ์ข์์ง์ง! ๐
โก ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฅ๋จ์
์ฅ์ :
โข ์คํ ํ์ผ ํฌ๊ธฐ๊ฐ ์์
โข ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ (์ฌ๋ฌ ํ๋ก๊ทธ๋จ์ด ํ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณต์ )
โข ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ์
๋ฐ์ดํธํ๋ฉด ์ฌ์ปดํ์ผ ๋ถํ์
โข ํ๋ฌ๊ทธ์ธ ์์คํ
๊ตฌํ ๊ฐ๋ฅ
โข ๋์คํฌ ๊ณต๊ฐ ์ ์ฝ
๋จ์ :
โข ๋ฐํ์ ์์กด์ฑ (๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ด ํ์)
โข ๋ฒ์ ์ถฉ๋ ๊ฐ๋ฅ์ฑ (DLL Hell)
โข ์ด๊ธฐ ๋ก๋ฉ ์๊ฐ์ด ์ฝ๊ฐ ๋ ๊ฑธ๋ฆผ
โข ๋ฐฐํฌ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ๋ ํจ๊ป ๋ฐฐํฌํด์ผ ํจ
๊ฐ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด๋ฒ์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ง๋ค์ด๋ณด์! ํค๋ ํ์ผ๊ณผ ๊ตฌํ ํ์ผ์ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์์ด. ๐
Step 1: Position Independent Code๋ก ์ปดํ์ผ
# Linux์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ฉ ์ค๋ธ์ ํธ ํ์ผ ์์ฑ
gcc -c -fPIC mymath.c -o mymath.o
# -fPIC ์ต์
์ค๋ช
:
# Position Independent Code๋ฅผ ์์ฑ
# ๋ฉ๋ชจ๋ฆฌ ์ด๋ ์์น์ ๋ก๋๋์ด๋ ๋์ ๊ฐ๋ฅํ ์ฝ๋
-fPIC ์ต์ ์ด ์ค์ํด! ์ด๊ฑด Position Independent Code๋ฅผ ์์ฑํ๋ผ๋ ์๋ฏธ์ธ๋ฐ, ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฉ๋ชจ๋ฆฌ์ ์ด๋ ์์น์๋ ๋ก๋๋ ์ ์์ด์ผ ํ๊ฑฐ๋ . ์ ๋ ์ฃผ์ ๋์ ์๋ ์ฃผ์๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ๋ง๋๋ ๊ฑฐ์ง. ๐ฏ
Step 2: ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ
# Linux์์ .so ํ์ผ ์์ฑ
gcc -shared -o libmymath.so mymath.o
# ๋๋ ํ ๋ฒ์ ์ปดํ์ผ๊ณผ ๋งํน
gcc -shared -fPIC mymath.c -o libmymath.so
# ์ฌ๋ฌ ์์ค ํ์ผ์ ํฌํจํ๋ ๊ฒฝ์ฐ
gcc -shared -fPIC mymath.c mystring.c myfile.c -o libmyutils.so
# ๋ฒ์ ์ ๋ณด๋ฅผ ํฌํจํ๋ ๊ฒฝ์ฐ
gcc -shared -Wl,-soname,libmymath.so.1 -o libmymath.so.1.0.0 mymath.o
๐ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ๊ด๋ฆฌ
์ค๋ฌด์์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฒ์ ๋ฒํธ๋ฅผ ๋ถ์ฌ์ ๊ด๋ฆฌํด:
libmymath.so.1.0.0 - ์ค์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ
libmymath.so.1 - ๋ฉ์ด์ ๋ฒ์ ์ฌ๋ณผ๋ฆญ ๋งํฌ
libmymath.so - ๊ฐ๋ฐ์ฉ ์ฌ๋ณผ๋ฆญ ๋งํฌ
์ด๋ ๊ฒ ํ๋ฉด API ํธํ์ฑ์ ์ ์งํ๋ฉด์ ์
๋ฐ์ดํธํ ์ ์์ด!
Step 3: ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ
# ์ปดํ์ผ (๋งํน)
gcc main.c -L. -lmymath -o myprogram
# ์คํ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ์ง์ (๋ฐฉ๋ฒ 1)
LD_LIBRARY_PATH=. ./myprogram
# ์คํ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ์ง์ (๋ฐฉ๋ฒ 2)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./myprogram
# rpath๋ฅผ ์ฌ์ฉํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ์คํ ํ์ผ์ ํฌํจ
gcc main.c -L. -lmymath -Wl,-rpath,. -o myprogram
./myprogram
โ ๏ธ ์ฃผ์์ฌํญ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ๋ฌธ์
๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ์ฅ ํํ ์ค๋ฅ๊ฐ "error while loading shared libraries: libmymath.so: cannot open shared object file"์ด์ผ. ์ด๊ฑด ์์คํ
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ ์ฐพ์ง ๋ชปํด์ ๋ฐ์ํ๋ ๊ฑฐ์ผ.
ํด๊ฒฐ ๋ฐฉ๋ฒ:
1. LD_LIBRARY_PATH ํ๊ฒฝ ๋ณ์ ์ค์
2. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์คํ
๊ฒฝ๋ก(/usr/lib, /usr/local/lib)์ ๋ณต์ฌ
3. /etc/ld.so.conf์ ๊ฒฝ๋ก ์ถ๊ฐ ํ ldconfig ์คํ
4. rpath ์ต์
์ผ๋ก ์คํ ํ์ผ์ ๊ฒฝ๋ก ํฌํจ
๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ง์ง ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋ฐํ์์ ํ์ํ ๋๋ง ๋ก๋ํ ์ ์๋ค๋ ๊ฑฐ์ผ! ์ด๊ฑธ ๋ช ์์ ๋งํน(Explicit Linking)์ด๋ผ๊ณ ํด. ํ๋ฌ๊ทธ์ธ ์์คํ ์ ๋ง๋ค ๋ ์ ๋ง ์ ์ฉํ์ง! ๐
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *handle;
int (*add_func)(int, int);
char *error;
// ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ก๋
handle = dlopen("./libmymath.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "Error: %s\n", dlerror());
return 1;
}
// ํจ์ ํฌ์ธํฐ ๊ฐ์ ธ์ค๊ธฐ
dlerror(); // ์ด์ ์๋ฌ ํด๋ฆฌ์ด
add_func = (int (*)(int, int))dlsym(handle, "add");
error = dlerror();
if (error != NULL) {
fprintf(stderr, "Error: %s\n", error);
dlclose(handle);
return 1;
}
// ํจ์ ํธ์ถ
printf("10 + 5 = %d\n", (*add_func)(10, 5));
// ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธ๋ก๋
dlclose(handle);
return 0;
}
// ์ปดํ์ผ ์ -ldl ์ต์
ํ์
// gcc dynamic_load.c -ldl -o dynamic_load
๐ dlopen API ํจ์๋ค
dlopen(): ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋
dlsym(): ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฌ๋ณผ(ํจ์/๋ณ์) ์ฃผ์๋ฅผ ๊ฐ์ ธ์ด
dlerror(): ๋ง์ง๋ง ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ฐํ
dlclose(): ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ์ธ๋ก๋
RTLD_LAZY: ํจ์๊ฐ ์ค์ ํธ์ถ๋ ๋ ์ฌ๋ณผ ํด์
RTLD_NOW: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ก๋ ์ ๋ชจ๋ ์ฌ๋ณผ ์ฆ์ ํด์
์ข์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ข์ ์ธํฐํ์ด์ค์์ ์์ํด! ํค๋ ํ์ผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ผ๊ตด์ด๋๊น ์ ๊ฒฝ ์จ์ ์์ฑํด์ผ ํด. ๐จ
// mylib.h - ์ ์ค๊ณ๋ ํค๋ ํ์ผ ์์
#ifndef MYLIB_H
#define MYLIB_H
#ifdef __cplusplus
extern "C" {
#endif
// ๋ฒ์ ์ ๋ณด
#define MYLIB_VERSION_MAJOR 1
#define MYLIB_VERSION_MINOR 0
#define MYLIB_VERSION_PATCH 0
// ํ๋ซํผ๋ณ export/import ๋งคํฌ๋ก
#ifdef _WIN32
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
#else
#define MYLIB_API __attribute__((visibility("default")))
#endif
// ์๋ฌ ์ฝ๋ ์ ์
typedef enum {
MYLIB_SUCCESS = 0,
MYLIB_ERROR_INVALID_PARAM = -1,
MYLIB_ERROR_OUT_OF_MEMORY = -2,
MYLIB_ERROR_NOT_FOUND = -3
} mylib_error_t;
// ๋ถํฌ๋ช
ํฌ์ธํฐ (Opaque Pointer) ์ฌ์ฉ
typedef struct mylib_context mylib_context_t;
// API ํจ์๋ค
MYLIB_API mylib_context_t* mylib_create(void);
MYLIB_API void mylib_destroy(mylib_context_t *ctx);
MYLIB_API mylib_error_t mylib_process(mylib_context_t *ctx, const char *input);
MYLIB_API const char* mylib_get_error_string(mylib_error_t error);
#ifdef __cplusplus
}
#endif
#endif // MYLIB_H
๐ก ํค๋ ํ์ผ ์ค๊ณ ํ
1. ์ธํด๋ฃจ๋ ๊ฐ๋: ์ค๋ณต ํฌํจ ๋ฐฉ์ง
2. C++ ํธํ์ฑ: extern "C" ์ฌ์ฉ
3. ๋ฒ์ ์ ๋ณด: ๋งคํฌ๋ก๋ก ๋ฒ์ ๊ด๋ฆฌ
4. ํ๋ซํผ ๋
๋ฆฝ์ฑ: ์กฐ๊ฑด๋ถ ์ปดํ์ผ ํ์ฉ
5. ๋ถํฌ๋ช
ํฌ์ธํฐ: ๊ตฌํ ์ธ๋ถ์ฌํญ ์จ๊ธฐ๊ธฐ
6. ์๋ฌ ์ฒ๋ฆฌ: ๋ช
ํํ ์๋ฌ ์ฝ๋ ์ ์
7. ๋ฌธ์ํ: ์ฃผ์์ผ๋ก API ์ค๋ช
์ถ๊ฐ
ABI(Application Binary Interface)๋ ๋ฐ์ด๋๋ฆฌ ๋ ๋ฒจ์์์ ์ธํฐํ์ด์ค์ผ. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๋ฐ์ดํธํ ๋ ABI ํธํ์ฑ์ ๊นจ๋จ๋ฆฌ๋ฉด ๊ธฐ์กด ํ๋ก๊ทธ๋จ๋ค์ด ์๋ํ์ง ์์ ์ ์์ด! ๐ฑ
๐ ABI ํธํ์ฑ์ ์ ์งํ๋ ๋ฐฉ๋ฒ
โ
์์ ํ ๋ณ๊ฒฝ:
โข ์๋ก์ด ํจ์ ์ถ๊ฐ
โข ๊ตฌ์กฐ์ฒด ๋์ ์ ํ๋ ์ถ๊ฐ (๋ถํฌ๋ช
ํฌ์ธํฐ ์ฌ์ฉ ์)
โข ํจ์ ๋ด๋ถ ๊ตฌํ ๋ณ๊ฒฝ
โข ์๋ก์ด ์๋ฌ ์ฝ๋ ์ถ๊ฐ
โ ์ํํ ๋ณ๊ฒฝ:
โข ๊ธฐ์กด ํจ์์ ์๊ทธ๋์ฒ ๋ณ๊ฒฝ
โข ๊ณต๊ฐ ๊ตฌ์กฐ์ฒด์ ํ๋ ์์๋ ํฌ๊ธฐ ๋ณ๊ฒฝ
โข ๊ธฐ์กด ํจ์ ์ญ์
โข ์ด๊ฑฐํ ๊ฐ ๋ณ๊ฒฝ
๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ ์ ๋ง ์ค์ํด! ๋๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๊ณ ๋๊ฐ ํด์ ํ๋์ง ๋ช ํํด์ผ ํด. ๐ง
// ์ข์ ์: ๋ช
ํํ ์์ ๊ถ
MYLIB_API char* mylib_create_string(const char *input) {
// ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
char *result = malloc(strlen(input) + 1);
if (result) {
strcpy(result, input);
}
return result;
}
MYLIB_API void mylib_free_string(char *str) {
// ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํด์
free(str);
}
// ์ฌ์ฉ ์
char *str = mylib_create_string("Hello");
// ... ์ฌ์ฉ ...
mylib_free_string(str);
// ๋ ๋ค๋ฅธ ์ข์ ํจํด: ์ฌ์ฉ์๊ฐ ๋ฒํผ ์ ๊ณต
MYLIB_API int mylib_get_string(char *buffer, size_t buffer_size) {
// ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๋ฒํผ์ ๋ณต์ฌ
if (buffer_size < required_size) {
return -1; // ๋ฒํผ ํฌ๊ธฐ ๋ถ์กฑ
}
strcpy(buffer, internal_string);
return 0;
}
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ฌ์ฉ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ฉด ์ค๋ ๋ ์์ ์ฑ์ ๊ณ ๋ คํด์ผ ํด! ๐
#include <pthread.h>
// ์ค๋ ๋ ์์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์
typedef struct {
int counter;
pthread_mutex_t mutex;
} mylib_context_t;
MYLIB_API mylib_context_t* mylib_create(void) {
mylib_context_t *ctx = malloc(sizeof(mylib_context_t));
if (ctx) {
ctx->counter = 0;
pthread_mutex_init(&ctx->mutex, NULL);
}
return ctx;
}
MYLIB_API void mylib_increment(mylib_context_t *ctx) {
pthread_mutex_lock(&ctx->mutex);
ctx->counter++;
pthread_mutex_unlock(&ctx->mutex);
}
MYLIB_API void mylib_destroy(mylib_context_t *ctx) {
if (ctx) {
pthread_mutex_destroy(&ctx->mutex);
free(ctx);
}
}
// ์ปดํ์ผ ์ -pthread ์ต์
ํ์
// gcc -shared -fPIC -pthread mylib.c -o libmylib.so
"๊ทธ๋์ ์ธ์ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๊ณ , ์ธ์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์จ์ผ ํด?" ์ด๊ฒ ๊ฐ์ฅ ๋ง์ด ๋ฐ๋ ์ง๋ฌธ์ด์ผ! ์ ๋ต์... ์ํฉ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค๋ ๊ฑฐ์ง. ๐ ๊ฐ๊ฐ์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ดํด๋ณด์!
| ์ํฉ | ์ถ์ฒ | ์ด์ |
|---|---|---|
| ์๋ฒ ๋๋ ์์คํ | ์ ์ | ๋จ์์ฑ, ์์ธก ๊ฐ๋ฅํ ๋์, ์์กด์ฑ ์์ |
| ํ๋ฌ๊ทธ์ธ ์์คํ | ๋์ | ๋ฐํ์ ๋ก๋ฉ, ์ ์ฐ์ฑ |
| ์์ฃผ ์ ๋ฐ์ดํธ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | ๋์ | ์ฌ์ปดํ์ผ ์์ด ์ ๋ฐ์ดํธ ๊ฐ๋ฅ |
| ๋ ๋ฆฝ ์คํํ ๋๊ตฌ | ์ ์ | ๋ฐฐํฌ ๊ฐํธ, ์์กด์ฑ ๋ฌธ์ ์์ |
| ์ฌ๋ฌ ํ๋ก๊ทธ๋จ์ด ๊ณต์ | ๋์ | ๋ฉ๋ชจ๋ฆฌ ํจ์จ, ๋์คํฌ ๊ณต๊ฐ ์ ์ฝ |
| ์ฑ๋ฅ์ด ์ต์ฐ์ | ์ ์ | ๋ก๋ฉ ์ค๋ฒํค๋ ์์ |
| ๋ผ์ด์ ์ค ์ ์ฝ | ์ํฉ์ ๋ฐ๋ผ | LGPL์ ๋์ ๋งํน ์ ํธ |
pkg-config๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ปดํ์ผ ๋ฐ ๋งํน ์ต์ ์ ๊ด๋ฆฌํ๋ ๋๊ตฌ์ผ. ๋ณต์กํ ์์กด์ฑ์ ๊ฐ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ์ ๋ง ์ ์ฉํด! ๐
# mymath.pc ํ์ผ ์์ฑ
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: MyMath
Description: Simple math library
Version: 1.0.0
Libs: -L${libdir} -lmymath
Cflags: -I${includedir}
# pkg-config ์ฌ์ฉ ์์
gcc main.c `pkg-config --cflags --libs mymath` -o myprogram
# ๋๋ Makefile์์
CFLAGS += $(shell pkg-config --cflags mymath)
LDFLAGS += $(shell pkg-config --libs mymath)
์ค๋ฌด์์๋ CMake๋ฅผ ๋ง์ด ์ฌ์ฉํด! Windows, Linux, macOS ๋ชจ๋์์ ๋์ํ๋ ๋น๋ ์์คํ ์ ๋ง๋ค ์ ์๊ฑฐ๋ . ๐
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyMath VERSION 1.0.0 LANGUAGES C)
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ค ํ์ผ
set(SOURCES
src/mymath.c
src/mystring.c
src/myfile.c
)
# ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ
add_library(mymath_static STATIC ${SOURCES})
set_target_properties(mymath_static PROPERTIES OUTPUT_NAME mymath)
# ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ
add_library(mymath_shared SHARED ${SOURCES})
set_target_properties(mymath_shared PROPERTIES
OUTPUT_NAME mymath
VERSION ${PROJECT_VERSION}
SOVERSION 1
)
# ํค๋ ํ์ผ ์ค์น ๊ฒฝ๋ก
target_include_directories(mymath_static PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_include_directories(mymath_shared PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# ์ค์น ๊ท์น
install(TARGETS mymath_static mymath_shared
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
)
install(DIRECTORY include/ DESTINATION include)
# ๋น๋ ๋ฐฉ๋ฒ
mkdir build
cd build
cmake ..
cmake --build .
sudo cmake --install .
๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ด๋ค ํจ์๋ฅผ ์ธ๋ถ์ ๊ณต๊ฐํ๊ณ ์ด๋ค ํจ์๋ฅผ ์จ๊ธธ์ง ์ ์ดํ๋ ๊ฑด ์ค์ํด! ์ด๋ ๊ฒ ํ๋ฉด ๋ค์์คํ์ด์ค ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌ๊ธฐ๋ ์ค์ผ ์ ์์ด. ๐
// visibility.h
#if defined(_WIN32) || defined(__CYGWIN__)
#ifdef BUILDING_DLL
#define PUBLIC_API __declspec(dllexport)
#else
#define PUBLIC_API __declspec(dllimport)
#endif
#define PRIVATE_API
#else
#if __GNUC__ >= 4
#define PUBLIC_API __attribute__((visibility("default")))
#define PRIVATE_API __attribute__((visibility("hidden")))
#else
#define PUBLIC_API
#define PRIVATE_API
#endif
#endif
// ์ฌ์ฉ ์
PUBLIC_API int public_function(int x);
PRIVATE_API int internal_function(int x); // ์ธ๋ถ์์ ์ ๊ทผ ๋ถ๊ฐ
# GCC์์ ๊ธฐ๋ณธ ๊ฐ์์ฑ์ hidden์ผ๋ก ์ค์
gcc -fvisibility=hidden -shared -fPIC mylib.c -o libmylib.so
์คํ ํ์ผ์ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด๋ค ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ๋ค์ด์ผ! ๐
# Linux์์ ldd ์ฌ์ฉ
ldd myprogram
# ์ถ๋ ฅ ์:
# linux-vdso.so.1 (0x00007ffd8e3f0000)
# libmymath.so => ./libmymath.so (0x00007f8e5c3a0000)
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e5c1a0000)
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ ์ฌ๋ณผ ํ์ธ
nm -D libmymath.so
# ๋๋
objdump -T libmymath.so
# ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด์ฉ ํ์ธ
ar -t libmymath.a
nm libmymath.a
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒ์ ๊ฒฝ๋ก ํ์ธ
ldconfig -p | grep mymath
# ์คํ ํ์ผ์ rpath ํ์ธ
readelf -d myprogram | grep RPATH
โ ๋ฌธ์ 1: undefined reference to 'function_name'
์์ธ: ๋งํน ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐพ์ง ๋ชปํจ
ํด๊ฒฐ:
โข -L ์ต์
์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ์ง์
โข -l ์ต์
์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด๋ฆ ์ง์
โข ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ ํ์ธ (์์กด์ฑ์ด ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค์)
โ ๋ฌธ์ 2: error while loading shared libraries
์์ธ: ๋ฐํ์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐพ์ง ๋ชปํจ
ํด๊ฒฐ:
โข LD_LIBRARY_PATH ํ๊ฒฝ ๋ณ์ ์ค์
โข /etc/ld.so.conf์ ๊ฒฝ๋ก ์ถ๊ฐ ํ ldconfig ์คํ
โข rpath ์ฌ์ฉํ์ฌ ๊ฒฝ๋ก๋ฅผ ์คํ ํ์ผ์ ํฌํจ
โ ๋ฌธ์ 3: ๋ฒ์ ์ถฉ๋ (Symbol version mismatch)
์์ธ: ์ฌ๋ฌ ๋ฒ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์คํ
์ ์กด์ฌ
ํด๊ฒฐ:
โข ์ฌ๋ณผ ๋ฒ์ ๋ ์ฌ์ฉ
โข ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ์ฐ์ ์์ ํ์ธ
โข ๊ฐ์ ํ๊ฒฝ์ด๋ ์ปจํ
์ด๋ ์ฌ์ฉ
์ด์ ๋ฐฐ์ด ๋ด์ฉ์ ๋ชจ๋ ํ์ฉํด์ ์ค์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด์! ๋ฌธ์์ด ์ฒ๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฒ์๋ถํฐ ๋๊น์ง ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ. ๐
mystring/
โโโ include/
โ โโโ mystring.h # ๊ณต๊ฐ ํค๋
โโโ src/
โ โโโ mystring.c # ๊ตฌํ
โ โโโ internal.h # ๋ด๋ถ ํค๋
โโโ tests/
โ โโโ test_mystring.c # ํ
์คํธ ์ฝ๋
โโโ examples/
โ โโโ example.c # ์ฌ์ฉ ์์
โโโ CMakeLists.txt # ๋น๋ ์ค์
โโโ mystring.pc.in # pkg-config ํ
ํ๋ฆฟ
โโโ README.md # ๋ฌธ์
#ifndef MYSTRING_H
#define MYSTRING_H
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// ๋ฒ์ ์ ๋ณด
#define MYSTRING_VERSION_MAJOR 1
#define MYSTRING_VERSION_MINOR 0
#define MYSTRING_VERSION_PATCH 0
// API export/import
#ifdef _WIN32
#ifdef MYSTRING_BUILD
#define MYSTRING_API __declspec(dllexport)
#else
#define MYSTRING_API __declspec(dllimport)
#endif
#else
#define MYSTRING_API __attribute__((visibility("default")))
#endif
// ์๋ฌ ์ฝ๋
typedef enum {
MYSTRING_OK = 0,
MYSTRING_ERROR_NULL_POINTER = -1,
MYSTRING_ERROR_OUT_OF_MEMORY = -2,
MYSTRING_ERROR_INVALID_ARGUMENT = -3
} mystring_error_t;
// ๋ฌธ์์ด ๊ฐ์ฒด (๋ถํฌ๋ช
ํฌ์ธํฐ)
typedef struct mystring mystring_t;
// ์์ฑ ๋ฐ ์๋ฉธ
MYSTRING_API mystring_t* mystring_create(const char *str);
MYSTRING_API mystring_t* mystring_create_empty(void);
MYSTRING_API void mystring_destroy(mystring_t *str);
// ๊ธฐ๋ณธ ์ฐ์ฐ
MYSTRING_API size_t mystring_length(const mystring_t *str);
MYSTRING_API const char* mystring_cstr(const mystring_t *str);
MYSTRING_API mystring_error_t mystring_append(mystring_t *str, const char *append);
MYSTRING_API mystring_error_t mystring_prepend(mystring_t *str, const char *prepend);
// ๊ฒ์ ๋ฐ ๋น๊ต
MYSTRING_API int mystring_compare(const mystring_t *str1, const mystring_t *str2);
MYSTRING_API bool mystring_equals(const mystring_t *str1, const mystring_t *str2);
MYSTRING_API int mystring_find(const mystring_t *str, const char *substr);
MYSTRING_API bool mystring_contains(const mystring_t *str, const char *substr);
// ๋ณํ
MYSTRING_API mystring_t* mystring_to_upper(const mystring_t *str);
MYSTRING_API mystring_t* mystring_to_lower(const mystring_t *str);
MYSTRING_API mystring_t* mystring_trim(const mystring_t *str);
// ๋ถํ ๋ฐ ๊ฒฐํฉ
MYSTRING_API mystring_t** mystring_split(const mystring_t *str, const char *delimiter, size_t *count);
MYSTRING_API mystring_t* mystring_join(mystring_t **strings, size_t count, const char *separator);
// ์๋ฌ ์ฒ๋ฆฌ
MYSTRING_API const char* mystring_error_string(mystring_error_t error);
#ifdef __cplusplus
}
#endif
#endif // MYSTRING_H
#include "mystring.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// ๋ด๋ถ ๊ตฌ์กฐ์ฒด ์ ์
struct mystring {
char *data;
size_t length;
size_t capacity;
};
// ๋ด๋ถ ํฌํผ ํจ์
static mystring_error_t ensure_capacity(mystring_t *str, size_t required) {
if (required <= str->capacity) {
return MYSTRING_OK;
}
size_t new_capacity = str->capacity * 2;
if (new_capacity < required) {
new_capacity = required;
}
char *new_data = realloc(str->data, new_capacity);
if (!new_data) {
return MYSTRING_ERROR_OUT_OF_MEMORY;
}
str->data = new_data;
str->capacity = new_capacity;
return MYSTRING_OK;
}
// ์์ฑ ๋ฐ ์๋ฉธ
mystring_t* mystring_create(const char *str) {
if (!str) {
return NULL;
}
mystring_t *result = malloc(sizeof(mystring_t));
if (!result) {
return NULL;
}
size_t len = strlen(str);
result->capacity = len + 1;
result->data = malloc(result->capacity);
if (!result->data) {
free(result);
return NULL;
}
strcpy(result->data, str);
result->length = len;
return result;
}
mystring_t* mystring_create_empty(void) {
mystring_t *result = malloc(sizeof(mystring_t));
if (!result) {
return NULL;
}
result->capacity = 16;
result->data = malloc(result->capacity);
if (!result->data) {
free(result);
return NULL;
}
result->data[0] = '\0';
result->length = 0;
return result;
}
void mystring_destroy(mystring_t *str) {
if (str) {
free(str->data);
free(str);
}
}
// ๊ธฐ๋ณธ ์ฐ์ฐ
size_t mystring_length(const mystring_t *str) {
return str ? str->length : 0;
}
const char* mystring_cstr(const mystring_t *str) {
return str ? str->data : NULL;
}
mystring_error_t mystring_append(mystring_t *str, const char *append) {
if (!str || !append) {
return MYSTRING_ERROR_NULL_POINTER;
}
size_t append_len = strlen(append);
size_t required = str->length + append_len + 1;
mystring_error_t err = ensure_capacity(str, required);
if (err != MYSTRING_OK) {
return err;
}
strcat(str->data, append);
str->length += append_len;
return MYSTRING_OK;
}
// ๋น๊ต
bool mystring_equals(const mystring_t *str1, const mystring_t *str2) {
if (!str1 || !str2) {
return false;
}
if (str1->length != str2->length) {
return false;
}
return strcmp(str1->data, str2->data) == 0;
}
// ๊ฒ์
int mystring_find(const mystring_t *str, const char *substr) {
if (!str || !substr) {
return -1;
}
char *pos = strstr(str->data, substr);
if (!pos) {
return -1;
}
return (int)(pos - str->data);
}
bool mystring_contains(const mystring_t *str, const char *substr) {
return mystring_find(str, substr) >= 0;
}
// ๋ณํ
mystring_t* mystring_to_upper(const mystring_t *str) {
if (!str) {
return NULL;
}
mystring_t *result = mystring_create(str->data);
if (!result) {
return NULL;
}
for (size_t i = 0; i < result->length; i++) {
result->data[i] = toupper((unsigned char)result->data[i]);
}
return result;
}
mystring_t* mystring_trim(const mystring_t *str) {
if (!str) {
return NULL;
}
const char *start = str->data;
const char *end = str->data + str->length - 1;
// ์์ชฝ ๊ณต๋ฐฑ ์ ๊ฑฐ
while (*start && isspace((unsigned char)*start)) {
start++;
}
// ๋ค์ชฝ ๊ณต๋ฐฑ ์ ๊ฑฐ
while (end > start && isspace((unsigned char)*end)) {
end--;
}
size_t new_len = end - start + 1;
mystring_t *result = malloc(sizeof(mystring_t));
if (!result) {
return NULL;
}
result->capacity = new_len + 1;
result->data = malloc(result->capacity);
if (!result->data) {
free(result);
return NULL;
}
memcpy(result->data, start, new_len);
result->data[new_len] = '\0';
result->length = new_len;
return result;
}
// ์๋ฌ ์ฒ๋ฆฌ
const char* mystring_error_string(mystring_error_t error) {
switch (error) {
case MYSTRING_OK:
return "Success";
case MYSTRING_ERROR_NULL_POINTER:
return "Null pointer error";
case MYSTRING_ERROR_OUT_OF_MEMORY:
return "Out of memory";
case MYSTRING_ERROR_INVALID_ARGUMENT:
return "Invalid argument";
default:
return "Unknown error";
}
}
#include <stdio.h>
#include "mystring.h"
int main() {
// ๋ฌธ์์ด ์์ฑ
mystring_t *str = mystring_create("Hello, World!");
if (!str) {
fprintf(stderr, "Failed to create string\n");
return 1;
}
printf("Original: %s\n", mystring_cstr(str));
printf("Length: %zu\n", mystring_length(str));
// ๋ฌธ์์ด ์ถ๊ฐ
mystring_error_t err = mystring_append(str, " Welcome to C!");
if (err != MYSTRING_OK) {
fprintf(stderr, "Error: %s\n", mystring_error_string(err));
mystring_destroy(str);
return 1;
}
printf("After append: %s\n", mystring_cstr(str));
// ๊ฒ์
if (mystring_contains(str, "World")) {
printf("String contains 'World'\n");
int pos = mystring_find(str, "World");
printf("Position: %d\n", pos);
}
// ๋๋ฌธ์ ๋ณํ
mystring_t *upper = mystring_to_upper(str);
if (upper) {
printf("Uppercase: %s\n", mystring_cstr(upper));
mystring_destroy(upper);
}
// ๊ณต๋ฐฑ ์ ๊ฑฐ
mystring_t *str2 = mystring_create(" trim me ");
mystring_t *trimmed = mystring_trim(str2);
if (trimmed) {
printf("Trimmed: '%s'\n", mystring_cstr(trimmed));
mystring_destroy(trimmed);
}
mystring_destroy(str2);
// ์ ๋ฆฌ
mystring_destroy(str);
return 0;
}
cmake_minimum_required(VERSION 3.10)
project(MyString VERSION 1.0.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# ์์ค ํ์ผ
set(SOURCES src/mystring.c)
set(HEADERS include/mystring.h)
# ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
add_library(mystring_static STATIC ${SOURCES})
target_include_directories(mystring_static PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
set_target_properties(mystring_static PROPERTIES OUTPUT_NAME mystring)
# ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
add_library(mystring_shared SHARED ${SOURCES})
target_include_directories(mystring_shared PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_definitions(mystring_shared PRIVATE MYSTRING_BUILD)
set_target_properties(mystring_shared PROPERTIES
OUTPUT_NAME mystring
VERSION ${PROJECT_VERSION}
SOVERSION 1
)
# ์์ ํ๋ก๊ทธ๋จ
add_executable(example examples/example.c)
target_link_libraries(example PRIVATE mystring_static)
# ์ค์น ๊ท์น
install(TARGETS mystring_static mystring_shared
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
)
install(FILES ${HEADERS} DESTINATION include)
# pkg-config ํ์ผ ์์ฑ
configure_file(mystring.pc.in mystring.pc @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/mystring.pc DESTINATION lib/pkgconfig)
์ฌ๊ธฐ๊น์ง C์ธ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์ ๋ํด ์ ๋ง ๋ง์ ๊ฑธ ๋ฐฐ์ ์ด! ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฐจ์ด๋ถํฐ ์ค์ ํ๋ก์ ํธ๊น์ง ๋ค๋ค์ผ๋, ์ด์ ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ณผ ์ค๋น๊ฐ ๋ ๊ฑฐ์ผ! ๐
ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์ด๋ C ํ๋ก๊ทธ๋๋ฐ์ ๋ํด ๋ ๊น์ด ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด, ์ฌ๋ฅ๋ท(https://www.jaenung.net)์์ ์ ๋ฌธ๊ฐ๋ค์ ๋์์ ๋ฐ์๋ณผ ์ ์์ด. ์ค๋ฌด ๊ฒฝํ์ด ํ๋ถํ ๊ฐ๋ฐ์๋ค์ด 1:1 ๋ฉํ ๋ง์ ์ ๊ณตํ๊ฑฐ๋ ! ํนํ ๋ณต์กํ ๋น๋ ์์คํ ๊ตฌ์ถ์ด๋ ํฌ๋ก์ค ํ๋ซํผ ๊ฐ๋ฐ ๊ฐ์ ๊ณ ๊ธ ์ฃผ์ ๋ ๊ฒฝํ์์ ์กฐ์ธ์ด ์ ๋ง ํฐ ๋์์ด ๋ผ. ๐ช
๋ํ ์ฌ๋ฅ๋ท์์๋ ์์ ์ด ๋ง๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ์ ์ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ๊ณต์ ํ๊ณ ์์ตํํ ์๋ ์์ด. ๋ค๊ฐ ๊ฐ๋ฐํ ์ ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ๋งคํ๊ฑฐ๋, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ๋ฒ์ ๊ฐ๋ฅด์น๋ ๊ฐ์๋ฅผ ์ฌ๋ฆด ์๋ ์์ง! ๐
๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์ ๋จ์ํ ์ฝ๋๋ฅผ ๋ชจ์๋๋ ๊ฒ ์ด์์ ์๋ฏธ๊ฐ ์์ด. ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ , ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ณ , ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ ์ฝ๋๋ฅผ ๋ง๋๋ ๊ฑฐ๋๊น! ์ด๊ฑด ์ง์ง ํ๋ก๊ทธ๋๋จธ๋ก ์ฑ์ฅํ๋ ๋ฐ ๊ผญ ํ์ํ ์คํฌ์ด์ผ. ๐ฑ
์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ์ ๋ฆฌํด๋ณด์๋ฉด:
๐ฏ ํต์ฌ ์์ฝ
1. ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (.a/.lib)
โข ์ปดํ์ผ ํ์์ ์คํ ํ์ผ์ ํฌํจ
โข ๋
๋ฆฝ์ ์คํ ๊ฐ๋ฅ
โข ์คํ ํ์ผ ํฌ๊ธฐ ์ฆ๊ฐ
โข ar ๋ช
๋ น์ด๋ก ์์ฑ
2. ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (.so/.dll)
โข ๋ฐํ์์ ๋ก๋
โข ๋ฉ๋ชจ๋ฆฌ ํจ์จ์
โข ์
๋ฐ์ดํธ ์ฉ์ด
โข -shared ์ต์
์ผ๋ก ์์ฑ
3. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค๊ณ ์์น
โข ๋ช
ํํ ์ธํฐํ์ด์ค
โข ABI ํธํ์ฑ ์ ์ง
โข ์ ์ ํ ์๋ฌ ์ฒ๋ฆฌ
โข ์ค๋ ๋ ์์ ์ฑ ๊ณ ๋ ค
โข ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ช
ํํ
4. ๋น๋ ์์คํ
โข CMake๋ก ํฌ๋ก์ค ํ๋ซํผ ์ง์
โข pkg-config๋ก ์์กด์ฑ ๊ด๋ฆฌ
โข ์ฌ๋ณผ ๊ฐ์์ฑ ์ ์ด
5. ๋๋ฒ๊น
๋๊ตฌ
โข ldd๋ก ์์กด์ฑ ํ์ธ
โข nm์ผ๋ก ์ฌ๋ณผ ๊ฒ์ฌ
โข readelf๋ก ๋ฐ์ด๋๋ฆฌ ๋ถ์
๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์ ์ฒ์์ ๋ณต์กํด ๋ณด์ผ ์ ์์ง๋ง, ํ ๋ฒ ์ต์ํด์ง๋ฉด ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ๊ฐ ๋ผ. ๋ค๊ฐ ๋ง๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ค๋ฅธ ํ๋ก์ ํธ์์ ์ฌ์ฌ์ฉ๋๊ณ , ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ฌ์ฉํ๋ ๊ฑธ ๋ณด๋ฉด ์ ๋ง ๋ฟ๋ฏํ๊ฑฐ๋ ! ๐
์ด์ ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด์ ์ค๋ ฅ์ ํค์๋ด. ์์ ์ ํธ๋ฆฌํฐ ํจ์๋ค๋ถํฐ ์์ํด์ ์ ์ ๋ณต์กํ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๊ฐ๋ฉด ๋ผ. ๊ทธ๋ฆฌ๊ณ ๋งํ๋ ๋ถ๋ถ์ด ์์ผ๋ฉด ์ฃผ์ ํ์ง ๋ง๊ณ ์ปค๋ฎค๋ํฐ๋ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์. ํ๋ก๊ทธ๋๋ฐ์ ํผ์ ํ๋ ๊ฒ ์๋๋ผ ํจ๊ป ์ฑ์ฅํ๋ ๊ฑฐ๋๊น! ๐ค
์, ์ด์ ํฐ๋ฏธ๋์ ์ด๊ณ ์ฒซ ๋ฒ์งธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ณผ ์๊ฐ์ด์ผ! ํ์ดํ ! ๐ปโจ
๐ ๋ณด๋์ค ํ: ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณต๋ถํ๊ธฐ
์ค๋ ฅ์ ๋น ๋ฅด๊ฒ ํฅ์์ํค๊ณ ์ถ๋ค๋ฉด ์ ๋ช
ํ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฝ๋๋ฅผ ์ฝ์ด๋ด:
โข zlib - ์์ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (๊ฐ๊ฒฐํ๊ณ ์ ์์ฑ๋ ์ฝ๋)
โข SQLite - ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ (๋จ์ผ ํ์ผ๋ก ๋ฐฐํฌ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ข์ ์)
โข libuv - ๋น๋๊ธฐ I/O ๋ผ์ด๋ธ๋ฌ๋ฆฌ (ํฌ๋ก์ค ํ๋ซํผ ์ค๊ณ์ ๋ชจ๋ฒ)
โข curl - HTTP ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (API ์ค๊ณ์ ์ข์ ์)
์ด๋ฐ ํ๋ก์ ํธ๋ค์ ๋ณด๋ฉด์ "์, ์ด๋ ๊ฒ ์ค๊ณํ๋๊ตฌ๋!" ํ๋ ์ธ์ฌ์ดํธ๋ฅผ ์ป์ ์ ์์ด!
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.