컴파일 시 헤더파일 중복으로 에러가 나는 경우우
c프로그램을 짜다 보면 종종 #include nex_port.h 를 했는데도 컴파일 시 nex_port.h에 정의된 함수를 찾을 수 없다는 에러를 종종 보기도 합니다.
그때는 #include nex_port.c 를 해주면 거의 모든 에러가 클리어 되던데요...
그런 걸 남용하다가 아래와 같은 문제가 생겼네요...
아래는 software.c 라는 소스입니다.
아래는 software.c 가 참조하고 있는 헤더파일들입니다.
여기에서 몇 개의 헤더들은 위에서 말한 바와 같이 헤더를 인클루드 했는데도 헤더에 정의 된 함수를 찾을 수 없다는 에러 때문에 본체가 정의된 *.c 소스까지 include 되어 있습니다.
예를 들자면 nex_image.c 나 nex_config.c 같은 것들인데요..
software.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <stddef.h> #include <sys/types.h> #include <unistd.h> #include <dirent.h> #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> #include <semaphore.h> #include "common.h" #include "nex_common.h" #include "nex_config.h" #include "nex_image.h" #include "software.h" #include "nex_pme.h" #include "nex_image.c" #include "nex_config.c"
여기서 참조된 nex_config.c 를 한 번 보겠습니다.
nex_config.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <time.h> #include <netinet/in.h> #include "common.h" #include "iocmd.h" #include "nex_common.h" #include "nex_config.h" #include "nex_system.h" #include "nex_system.c" #include "nex_interface.h" #include "nex_password.h" #include "nex_port.h" #include "nex_pme.h" #include "nex_qos.h" #include "nex_pme.c" #include "nex_port.c" #include "nex_efmoam.c" #include "nex_igmp.c" #include "nex_vlan.c" #include "nex_http.h" #include "nex_snmp.h" #include "nex_image.h" #include "nex_vlan.h" #include "nex_filter.h" #include "nex_dtag.h" #include "nex_efmoam.h" #include "nex_sntp.h" #include "nex_log.h" #include "nex_tm.h" #include "nex_module.h" #include "nex_igmp.h" #include "nex_cpe.c" #include "bdFlashCommon.h" #include "crc32.h"
nex_config.c 역시도 함수 본체가 정의된 *.c가 많이 포함되어 있습니다.
nex_port.c, nex_vlan.c, nex_cpe.c 등등이 있겠는데요.
여기서 nex_port.c 를 한 번 보도록 하겠습니다.
nex_port.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include "common.h" #include "iocmd.h" #include "nex_common.h" #include "nex_system.h" #include "nex_port.h" #include "nex_config.h" #include "nex_pme.h" #include "nex_qos.h" #include "nex_vlan.h" #include "nex_common.c" #include "nex_module.h" #include "nex_module.c"
여기에도 역시 함수 본체가 정의된 *.c 파일이 많이 있습니다.
문제는 맨 위의 software.c를 컴파일 하면 아래와 같은 에러가 나온다는 겁니다.
running: ppc_82xx-gcc -g -O2 -Dlinux -I. -I/home/test/install/usr/include -o software netsnmptmp.18014.c -pthread software.c -L/home/test/install/usr/lib -lnetsnmpmibs -lnetsnmpagent -lnetsnmphelpers -lnetsnmp -ldl -lcrypto -lm In file included from nex_port.c:21, from nex_config.c:25, from software.c:25: nex_common.c:25: error: redefinition of 'nexGetFromFile' nex_common.c:25: error: previous definition of 'nexGetFromFile' was here nex_common.c:49: error: redefinition of 'nexSetToFile' nex_common.c:49: error: previous definition of 'nexSetToFile' was here nex_common.c:85: error: redefinition of 'nexGetFromFileConf' nex_common.c:85: error: previous definition of 'nexGetFromFileConf' was here nex_common.c:109: error: redefinition of 'nexSetToFileConf' nex_common.c:109: error: previous definition of 'nexSetToFileConf' was here nex_common.c:146: error: redefinition of 'nexAddToFileConf' nex_common.c:146: error: previous definition of 'nexAddToFileConf' was here nex_common.c:163: error: redefinition of 'nexRunCmd' nex_common.c:163: error: previous definition of 'nexRunCmd' was here nex_common.c:242: error: redefinition of 'nexRunCmdBack' nex_common.c:242: error: previous definition of 'nexRunCmdBack' was here nex_common.c:283: error: redefinition of 'nexExecCmd' nex_common.c:283: error: previous definition of 'nexExecCmd' was here nex_common.c:294: error: redefinition of 'nex_xrealloc' nex_common.c:294: error: previous definition of 'nex_xrealloc' was here nex_common.c:304: error: redefinition of 'find_pid_by_name' nex_common.c:304: error: previous definition of 'find_pid_by_name' was here nex_common.c:372: error: redefinition of 'nexGetPid' nex_common.c:372: error: previous definition of 'nexGetPid' was here nex_common.c:383: error: redefinition of 'find_pid' nex_common.c:383: error: previous definition of 'find_pid' was here nex_common.c:396: error: redefinition of 'isnumber' nex_common.c:396: error: previous definition of 'isnumber' was here nex_common.c:406: error: redefinition of 'cksum16' nex_common.c:406: error: previous definition of 'cksum16' was here nex_common.c:418: error: redefinition of 'nexcmp' nex_common.c:418: error: previous definition of 'nexcmp' was here nex_common.c:437: error: redefinition of 'nexncmp' nex_common.c:437: error: previous definition of 'nexncmp' was here In file included from nex_port.c:23, from nex_config.c:25, from software.c:25: nex_module.c:27: error: redefinition of 'nexFindValue' nex_module.c:27: error: previous definition of 'nexFindValue' was here nex_module.c:59: error: redefinition of 'nexGetModuleState' nex_module.c:59: error: previous definition of 'nexGetModuleState' was here nex_module.c:95: error: redefinition of 'nexSendModuleCommand' nex_module.c:95: error: previous definition of 'nexSendModuleCommand' was here nex_module.c:173: error: redefinition of 'nexGetModuleBoardType' nex_module.c:173: error: previous definition of 'nexGetModuleBoardType' was here nex_module.c:183: error: redefinition of 'nexSetModuleBoardType' nex_module.c:183: error: previous definition of 'nexSetModuleBoardType' was here nex_module.c:198: error: redefinition of 'nexGetModuleInfo' nex_module.c:198: error: previous definition of 'nexGetModuleInfo' was here nex_module.c:228: error: redefinition of 'nexSetModuleDeviceType' nex_module.c:228: error: previous definition of 'nexSetModuleDeviceType' was here nex_module.c:252: error: redefinition of 'nexSetModuleDeviceMode' nex_module.c:252: error: previous definition of 'nexSetModuleDeviceMode' was here nex_module.c:276: error: redefinition of 'nexSetModuleOperMode' nex_module.c:276: error: previous definition of 'nexSetModuleOperMode' was here nex_module.c:300: error: redefinition of 'nexSetModuleDesc' nex_module.c:300: error: previous definition of 'nexSetModuleDesc' was here nex_module.c:321: error: redefinition of 'nexGetConfigModule' nex_module.c:321: error: previous definition of 'nexGetConfigModule' was here nex_module.c:331: error: redefinition of 'nexBuildConfigModule' nex_module.c:331: error: previous definition of 'nexBuildConfigModule' was here removing the tmporary code file: netsnmptmp.18014.c
에러의 요지는 함수들이 중복 선언되었다는 것입니다.
그렇다고 위의 소스들에서 중복되는 부분의 헤더를 지울수는 없습니다. 그들은 다른 소스에서도 참조하고 있고
인클루드된된 헤더를 지우면 "함수를 찾을 수 없다"는 에러가 반드시 나오기 때문이죠...
제가 길게 설명했는데.. 문제의 요지가 잘 전달되었을 지 의아하군요...
부디 이런 문제를 격으신 분이 있거나 해결책을 알고 계신 분이 계시면 도움을 좀 부탁드립니다.
그럼 오늘도 좋은 하루 보내세요.
애초에 include로
애초에 include로 c파일을 부른 것 자체가 잘못입니다.
정의된 함수가 header에 선언되지 않았다면, header를 고치면 될 일이고,
만약 어떤 이유로 header를 고쳐서는 안된다면, 따로 header를 만들거나, 그 함수를 사용하는 모듈에서 선언해서 쓰면 될 일입니다.
------------------------------
How many legs does a dog have?
------------------------------
How many legs does a dog have?
부연설명을 하자면
해더에는 분명히 함수가 선언되어 있어요. 근데 컴파일 하면 함수를 못찼겠다고 에러가 나온다는 겁니다.
그래서 어쩔 수 없이 c 파일을 인클루드 시켜봤는데 에러가 클리어되더라는 거죠...
이번 에러가 난 건에 대해서는 말씀하신 대로 필요한 함수를 "사용하는 모듈"로 카피해서 사용할 수도 있는데
그럴 경우 그 함수가 참조하는 다른 함수들을 사용하기 위해서 또 다른 헤더들을 인크루드 시켜야 되고
해더 인클루드로 해결되면 되는데 함수를 정의한 함수의 해더를 인클루드 시켰는데도 그 함수 못찾겠다고 에러가 나면
어쩔 수 없이 c 파일을 incldue 시킬 수 밖에 없다는 겁니다...
예를 들면
1. nex_port.h 에 port_init가 정의되어 있습니다.
2. software.c 에서 include nex_port 해서 port_init를 쓰려고 합니다.
3. software를 컴파일하면 port_init가 정의되지 않은 함수라고 나옵니다.
경우1
1. software.c 에 #include nex_port.c 를 해줍니다.
2. 에러가 클리어 됩니다.
경우2
1. software.c에 port_init함수를 선언하고 그 함수가 사용하고 있는 다른 함수들을 사용하기 위해서 다른 해더들을 인클루드 합니다.
2. software.c에 port_init 함수를 nex_port에서 복사해서 붙입니다.
3. 컴파일 합니다.
4. port_init가 참조하는 함수들을 사용하기 위해서 인클루드한 헤더에서 에러가 나옵니다.
5. 살펴보니 인클루드 한 헤더에 이미 정의되어 있는 함수들인데 또 정의가 안되었다고 에러를 뿜습니다.
6. 다시 그 헤더의 c 함수를 인클루드 합니다.
7. 컴파일 하니 빛의 속도로 화면이 넘어가면서 에러가 나옵니다.
경우2는 님이 말씀하신 것을 토대로 한 번 해본 겁니다.
그런데도... 역시나 문제가 있네요...
에고... 제가 뭔가 잘못한 건가요?
다른 방법이 있으시면 말씀 좀 해주세요...
일단 함수를 왜
일단 함수를 왜 못찾는지부터 알아야겠죠.
이 이유를 찾지 않고 그저 에러를 없애려고만 하면 근본적인 문제가 해결이 안되잖아요.
static으로 정의한 건지, 또다른 이유가 있는지, header에서 define이 꼬이는지 다 따져봐야하는거 아닌가요?
정석을 쓰지않고, 쉽게 돌아갈 방법을 찾으니 나중에 답이 안나올 수 밖에 없지요.
그리고 port_init함수를 복사하는 건 제가 말한적 없습니다. 정의가 아니고 선언입니다. definition이 아니라 declaration요. 개인적인 생각으로, 중복된 정의는 include로 c를 불러오는 것 보다 더 나쁜(?)짓입니다.
그냥 선언만 제대로 하면 되는데 복사는 해서도 안되고 할 필요도 없지요.
경 3
1. 왜 port_init 함수를 못찾는지 알아봅니다.
2. port_init 함수가 제대로 선언(또는 정의)되도록 수정합니다.
3. 서로 다른 라이브러리가 같은 이름을 쓰거나 define 구문때문에 충돌이 나는 등, 피치 못할 사정이 있다면, nex_port.h를 분리하고(또는 분리하거나) software.c를 분리합니다.
4. 구현 문제로 차마 분리하지 못할 경우라면, wrapper.h/c 를 만들어서 한번 더 싸서 분리해줍니다.
에러 메시지를 없애는게 급선무가 아니고, 에러가 왜 나는지 찾는게 급선무입니다.
------------------------------
How many legs does a dog have?
------------------------------
How many legs does a dog have?
음...
include 해서 사용하는 소스코드는 그 자체로 paste 된 것과 동일하게 사용되기 때문에..
굳이 헤더를 include 할 필요는 없습니다.
위 오류는 모두 중복선언과 관련되 내용인데..
header 를 여러 헤더에서 include 시에 중복 선언 등의 에러가 나는 걸 방지하려면..
#ifndef _A_HEADER_H__
#define _A_HEADER_H__
.. contents of a.h
#endif /* _A_HEADER_H__ */
와 같이, #ifdef 로 감싸 주면 됩니다.
그리고 예시에서 undefined symbol 이 뜨는 경우라면...
port_init 의 implementation 이 있는 object file 을 찾지 못했을 경우일겁니다.
예를 들면 port_init 의 구현이 nex_port.c 에 있는데..
얘를 포함하여 빌드하지 않고, 다른 소스에서 단지 header 만 include 한 경우라는 뜻입니다.
컴파일은 되지만 linker 가 port_init 을 못찾겠다고 툴툴댈겁니다.
코드를 싹 뜯어내서, 헤더와 코드를 분리하고...
include 대신 모듈 컴파일을 하는것이 좋을 것 같네요.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
감사
감사
class
비슷한 경우로 C++에서 class를 못 찾는 에러가 있습니다.
예를 들어,
---- A.h ----
#ifndef A_H
#define A_H
#include"B.h"
class A{
B b;
}
#endif
---- B.h ----
#ifndef B_H
#define B_H
#include"A.h"
class B{
A a;
}
#endif
위와 같은 상황이 있을 때, B.h에서 class A가 없다는 컴파일 에러가 발생하는 경우가 있습니다.
이 때, B.h를
#ifndef B_H
#define B_H
#include"A.h"
class A;
class B{
A a;
}
#endif
와 같이 고치면, class A; 구문이 A.h 의 A class를 찾아가기에 컴파일 타임과 런타임 둘 다 정상적으로 작동합니다.
댓글 달기