link시에 라이브 러리에 있는데 자꾸 없다라는 메세지의 원인은

cbycby의 이미지

현재 Microwindows 를 이용해서 Embedded Target 시스템용 UI를 테스트 하고 있는 중에 문제가 발생하였습니다. :cry:

아래를 보면, libmwengine.a 파일에 보면 분명히 GdDrawImageFromFile 이라는 함수가 들어 있습니다.

[korone@koronelinux lib]$ nm libmwengine.a  | grep DrawImage
00000e70 T GdDrawImage
         U GdDrawImage
000016a8 T GdDrawImageFromBuffer
000017d8 T GdDrawImageFromFile
00000000 T GdDrawImageToFit

이를 아래와 같이 컴파일 하는데...
아래는 Makefile 내용중 일부입니다.

중략 ... 
MWINLIBS = \
    $(MWINPATH)/lib/libmwin.a \
    $(MWINPATH)/lib/libmwinlib.a\
    $(MWINPATH)/lib/libmwengine.a \
    $(MWINPATH)/lib/libmwdrivers.a \
    $(MWINPATH)/lib/libmwfonts.a \
    $(MWINPATH)/lib/libmwimages.a \
    $(MW_CORE_LIBS)
FT2LIB = $(FT2PATH)/objs/.libs/libfreetype.a
PIMWLIBS = gui01_main.o ../../mwgui/libpimwgui.a

INC=-I../../common -I../../lib -I../../mwgui -I$(MWINPATH)/include -I$(FT2PATH)/include
#LIBS=$(MWINLIBS) $(FT2PATH)/objs/.libs/libfreetype.a gui01_main.o ../../mwgui/libpimwgui.a
LIBS=$(MWINLIBS) $(FT2LIB) $(PIMWLIBS)
중략 ... 
@sh -c 'for i in $(OUT); do echo making $$i...; $(CXX) $(CFLAGS) $(INC) $(LFLAGS) -o $$i $$i.cc $(LIBS); if [ $$? -ne 0 ]; then exit 1; fi; done'

이와 같이 컴파일 하는데...
대체 분명 컴파일 시에도 libmwengine.a 를 포함시켰는데... 왜 자꾸

Quote:

undefined reference to `GdDrawImageFromFile(_mwscreendevice*, int, int, int, int, char*, int)'

라는 에러가 나타나는 것일까요?
이것때문에 일이 안되네요... :(

조병완
http://www.korone.net

hwang의 이미지

c의 header를 특별한 guard없이 c++파일에서 직접
include한것으로 짐작이 되네요.
GdDrawImageFromFile를 정의한 header를 foo.h라고 하면
extern "C" {
#include "foo.h"
}
이런 식으로 c++파일에서 include 하세요.

cbycby의 이미지

지금 테스트 해봐야겠습니다. :D

http://www.korone.net QT 커뮤니티 사이트

cbycby의 이미지

C 헤더를 include 한 곳 마다 extern "C" { }; 로 내부를 처리했는데도 결과가 마찬가지네요...

대체 이일을 어찌해야 할까요?

다른 방법으로 해결책 알고 계신분 있나요?

이것때문에 오늘 아무것도 못했어요 ㅜ.ㅡ

http://www.korone.net QT 커뮤니티 사이트

kslee80의 이미지

직접 작성한 코드들중에 해당 함수를 사용한 부분이 있는지요?
그렇다면 저 프로토타입에 '완벽하게' 들어맞는지를 확인해야 합니다.

라이브러리에 포함된 함수가 저 함수를 부를때,
해당 함수가 프로토타입을 잘못 맞춰서 부르는 경우도
저런 문제가 생길수 있습니다.

C 와 틀리게 C++ 은 함수 프로토타입 체크가 엄격해서,
약간만이라도 틀리면 바로 undefined 에러를 만나게 됩니다.
(물론, undefined 에러가 나는 이유는..
C++ 은 Overloading 을 지원하는 언어이기 때문이죠.)

만약에 두번째 문제라면 많이 골치아퍼집니다;;
라이브러리들의 소스를 구해서 잘못 맞춘 프로토타입을 다 맞춰준 다음
재컴파일해서 사용하거나,
아니면 C++ 을 사용한 코드들을 모두 다 C 로 바꿔야 할겁니다.;

voider의 이미지

컴파일 과정에서 나온 에러인지 링크 과정에서 나온 에러인지
명확히 해주세요.

전자라면 kslee80님 답변이 설득력이 있네요

-- 아쉬운 하루 되세요 --

cbycby의 이미지

Quote:
컴파일 과정에서 나온 에러인지 링크 과정에서 나온 에러인지
명확히 해주세요.

링크과정에서 나오는 에러입니다.

흠... 또 문제들을 살펴 보아야겠군요...

기존 몇몇 라이브러리들이 링크가 잘 되는것으로 봐서는(전체 5개중 1개만 그러한 증상을 일부 라이브러리의 문제인것으로 보이는데...

http://www.korone.net QT 커뮤니티 사이트

yeppiguy의 이미지

저두 지금 동일한 현상에 시달리고 있습니다.

사실은 이런 경우가 발생하면, 링크시에 나열하는 라이브러리나 오브젝트 파일의 위치를 바꾸면 더 많은 undefined reference에러가 발생하거나 사라지는 기묘한(?) 현상이 발생하더군요.

몇번의 시행착오를 거쳐 겨우 해결되어서 문제없이 링킹을 하다가... 어느날 좀 많은 부분의 코드가 추가되거나 수정되면서 또 유사한 문제가 발생하곤 했어요...

위의 님들께서 말씀하신대로 extern "C"라던지 extern선언부, 그리고 프로토타입 missmatch 등등 안해 본게 없지만 다 마찬가지였습니다.

링킹시 .a파일을 오브젝트 파일처럼 링킹도 해 보고, -l라이브러리로 링킹도 해보고 다 해봤지만(물론 -L로 위치지정도 확인했구요), 여간해서 잘 사라지질 않더군요... 자리만 요목조목 잘 끼워맞춰서 넘어가면 다행이긴 하지만, 여간 찜찜하지 않더라고요.

왜냐면 다음번 업데이트에 또 문제가 발생할지도 모르니까요...

어쨌든 이부분을 완전히 해결할려면 사용하시는 덩치 큰 라이브러리를 동적라이브러리로 만드셔야 합니다. 그러면 이런 문제는 완전히 사라집니다.
(유추하건대... 링킹시에 사용하는 offset범위를 초과하거나 링커의 오류인걸로 추측은 하지만, 정확한 원인은 모르겠네요. 아무튼 실행시에 주소가 결정되는 동적라이브러리라면 이런문제를 고려하지 않아도 되겠지요.)

하지만, 저두 임베디드 쪽 작업을 하는데, 동적라이브러리를 사용하는 거 자체를 부담스러워 하는 경우에는 다른 방법이 없나 고민하게 되지요.

오늘도 그 고민을 하다가 우연히 저랑 비슷한 고민을 하신 분이 계신거 같아서 이렇게 몇자 적습니다......

예전에 누가 올려둔 글묶음입니다..도움이 되실지 모르겠네요.
http://bbs.kldp.org/viewtopic.php?t=535&highlight=undefined+reference

vinus의 이미지

저두 동일한 현상에 시달린 적이 있습니다.
그때 해결방법은 yeppiguy님의 말씀대로

링크시에 나열하는 라이브러리나 오브젝트 파일의 위치를 바꾸면 이방법을 사용 했었습니다.

그리고, 프로젝트의 자체 라이버러리를 통합하는 과정을 거쳤던 기억이 있습니다.
여러개로 쪼개어진 라이버러리를 하나로 묶어 버리는 작업을 했었던... --> 이게 삽잘이었을까요..

누군가 더 좋은 해결 방법이 있으면.. 제발 알려 주세요.

>>>행복한 웃음<<<

aqwerf의 이미지

yeppiguy wrote:
사실은 이런 경우가 발생하면, 링크시에 나열하는 라이브러리나 오브젝트 파일의 위치를 바꾸면 더 많은 undefined reference에러가 발생하거나 사라지는 기묘한(?) 현상이 발생하더군요.

이 문제가 발생하는 가장 큰 이유는 library module 이나 object file들이 서로 상호 참조를 하는 구조로 작성되었을 때 입니다. 또는 link 순서를 잘못 적어준 경우에도 발생합니다.

간단하게 예를 들면

libTestA.a 내의 두 파일이 다음과 같은 경우 

< fileA.c > 
void funcA() { 
  funcC(); 
}

< fileB.c>
void funcB() {
}

libTestB.a

<fileX.c>
void funcC() {
  funcB();
}

위와 같이 libTestA에서 libTestB를 참조하고(funcC()), 다시 libTestB에서 libTestA를 참조(funcB())하는 경우와 같을 때 발생합니다.

ld -o output main.o libTestA.a libTestB.a

위와 같이 link를 하면 funcB()가 없다고 에러가 나죠...
간단하게 해결하려면 물론 다음과 같이 하면 해결은 되나 좋은 방법은 아니죠.

ld -o output main.o libTestA.a libTestB.a libTestA.a

상용 toolchain 중에서는 link시에 library가 모두 resolve 될 때까지 계속 recursive하게 library를 search하는 경우도 있지만(diab compiler가 이러던것 같았는데...) gnu ld의 경우 link시의 적어준 순서데로 왼쪽부터 오른쪽으로 한번씩만 search를 하여 link합니다.

일반적으로 module을 layering하여 각각의 layer마다 따로 library를 만들고 이를 link 시에 상위 layer먼저 적어주기 때문에 이런 현상이 발생하지 않습니다.

library를 만들때 이와 같이 여러 library들이 상호 참조하는 구조는 바람직하지 않습니다.
이런 경우 link시에 에러 출력결과를 보고 에러 출력된 소스파일내에 관련 함수를 호출하는 곳을 찾아
- library간에 상호 참조하는 경우인지
- 아니면 link시에 library순서를 잘못 쓴것인지
원인을 찾아보고 그렇게 되지 않도록 수정하여야 합니다.
아니면 속편하게 gnu ld의 -( xxx -) option을 사용하면 recursive search가 가능합니다.

자세한 사항은 gnu ld manual을 참조하세요.

http://www.fsf.org/software/binutils/manual/ld-2.9.1/html_mono/ld.html

Quote:

-larchive
--library=archive
Add archive file archive to the list of files to link. This option may be used any number of times. ld will search its path-list for occurrences of libarchive.a for every archive specified. On systems which support shared libraries, ld may also search for libraries with extensions other than .a. Specifically, on ELF and SunOS systems, ld will search a directory for a library with an extension of .so before searching for one with an extension of .a. By convention, a .so extension indicates a shared library. The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again. See the -( option for a way to force the linker to search archives multiple times. You may list the same archive multiple times on the command line. This type of archive searching is standard for Unix linkers. However, if you are using ld on AIX, note that it is different from the behaviour of the AIX linker.

-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or `-l' options. The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references are resolved. Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.

pynoos의 이미지

[korone@koronelinux lib]$ nm libmwengine.a  | grep DrawImage
00000e70 T GdDrawImage
         U GdDrawImage
000016a8 T GdDrawImageFromBuffer
000017d8 T GdDrawImageFromFile
00000000 T GdDrawImageToFit

중략 ... 

undefined reference to `GdDrawImageFromFile(_mwscreendevice*, int, int, int, int, char*, int)'

위의 코드는 틀림없이(:)) C library의 Header에 extern "C"이 선언이 안되어 C++ 코드에서 mangling이 일어나서 링크 오류가 발생하는 것입니다.

확인 방법은 일단

nm -A *.o *.a | grep GdDrawImageFromFile

모든 오브젝트와 라이브러리에서 T로 된것과 U 로 된 것이 제대로 존재하는지 확인하면 됩니다.

nm -AC *.o *.a | grep GdDrawImageFromFile

로도 해보세요.

-A 옵션은 이런 오류를 찾는데 아주 유용합니다.

aqwerf의 이미지

위의 것은 c, c++ 문제가 아니라 link시 option 순서가 문제일 확률이 가장 높습니다.

LIBS=$(MWINLIBS) $(FT2LIB) $(PIMWLIBS)

로 되어 있는데 PIMWLIBS에 gui01_main.o 가 포함 되어 있네요.

아마 gui01_main.o에서 에러나는 함수를 참조하는 것 같은데 다음과 같이 하면 해결 될 겁니다.

LIBS=gui01_main.o $(MWINLIBS) $(FT2LIB) $(PIMWLIBS)

물론 PIMWLIBS에서는 gui01_main.o를 빼야죠.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.