|
6. 프로그래밍 관련 질문
6.1. 패키지는 어떻게 기여하나요?
6.2. 시그윈에 어떻게 기여하나요?
6.3. 컴파일된 실행 파일은 왜 그렇게 큰가요?!!?
6.4. 애플리케이션을 64비트 시그윈으로 포팅할 때 주의해야 할 점은 무엇인가요?
6.5. 제 프로젝트가 64비트 시그윈에서 전혀 빌드되지 않습니다. 무슨 일이죠?
6.6. 64비트용으로 __CYGWIN64__가 정의되지 않은 이유는 무엇인가요?
6.7. glibc는 어디에 있나요?
6.8. 오브젝티브 C는 어디에 있나요?
6.9. 시그윈에서 실행 오류와 함께 메이크가 실패하는 이유는 무엇인가요?
6.10. IPC를 사용하려면 어떻게해야합니까, 또는 왜 시스템 호출 오류가 발생합니까?
6.11. WinMain@16에 대한 정의되지 않은 참조는 왜 발생하나요?
6.12. 윈도우 에이피아이 호출은 어떻게 사용하나요?
6.13. 시그윈을 사용하지 않는 윈도우 실행 파일을 컴파일하려면 어떻게 해야 하나요?
6.14. 런타임에 cygwin1.dll이 필요 없는 시그윈 프로그램을 빌드할 수 있나요?
6.15. MSVCRT*.디엘엘과 cygwin1.dll을 모두 링크할 수 있나요?
6.16. 콘솔 창을 사라지게 하려면 어떻게 해야 하나요?
6.17. '구분 기호 누락'에 대해 불만을 제기하는 이유는 무엇인가요?
6.18. 마이크로소프트의 윈도우 에이피아이 헤더를 재배포할 수 없는 이유는 무엇인가요?
6.19. 비쥬얼 스튜디오 또는 Mingw-w64에서 cygwin1.dll을 어떻게 사용하나요?
6.20. .lib 파일에 대해 어떻게 링크하나요?
6.21. 시그윈을 직접 빌드하려면 어떻게 해야 하나요?
6.22. 시그윈에서 버그를 발견했는데 어떻게 디버깅할 수 있나요(gdb의 기호가 이상하게 보입니다)?
6.23. 지원되지 않는 플랫폼(파워PC, 알파, ARM, 아이테니엄)에서 시그윈을 컴파일하려면 어떻게 해야 하나요?
6.24. 애플리케이션의 힙/스택 크기를 조정하려면 어떻게 해야 하나요?
6.25. 실행 파일에 필요한 디엘엘을 어떻게 찾을 수 있나요?
6.26. 디엘엘은 어떻게 빌드하나요?
6.27. mainCRTStartup에서 중단점을 설정하려면 어떻게 해야 하나요?
6.28. 무슨 일이 일어나고 있는지 디버깅하려면 어떻게 해야 하나요?
6.29. 시스템 추적 메커니즘을 대신 사용할 수 있나요?
6.30. gdb는 신호를 어떻게 처리하나요?
6.31. 링커가 무언가를 찾을 수 없다고 불평한다.
6.32. 구조체 stat64를 사용하면 왜 에러가 발생하나요?
6.33. libc에 대해 링크된 디엘엘을 만들 수 있나요?
6.34. malloc.h는 어디에 있나요?
6.35. 나만의 malloc을 사용할 수 있나요?
6.36. msvc++와 gcc로 컴파일한 객체를 섞어서 사용할 수 있나요?
6.37. gdb 디버거를 사용하여 VC++로 빌드한 프로그램을 디버깅할 수 있나요?
6.38. 내 메이크파일에서 셸 스크립트가 제대로 실행되지 않나요?
6.39. 어떤 전처리기 매크로에 대해 알아야 하나요?
6.40. 유닉스 지유아이를 윈도우로 포팅하려면 어떻게 해야 하나요?
6.1. 패키지는 어떻게 기여하나요?
패키지 관리자가 되고 싶으시다면 정말 좋습니다! 시그윈 팀의 우선 순위는 사이그윈 그 자체이므로 패키지를 준비하고 유지 관리할 자원자가 절실히 필요합니다.
시그윈 패키지 기여자 가이드(https://cygwin.com/packages.html)에 시그윈 패키지에 대해 알아야 할 모든 것이 자세히 나와 있습니다.
패키지 유지 관리에 대한 질문이 있는 경우, cygwin-apps 메일링 리스트(https://cygwin.com/lists.html 에서 시작)에서 검색 및 탐색한 후 cygwin-apps 목록 아카이브를 이용하세요. 패키지 제출 체크리스트(https://cygwin.com/packaging-contributors-guide.html#submitting)를 참조하여 사이버윈-앱스에 ITP(패키지 제출 의도) 이메일을 보내기 전에 반드시 확인하시기 바랍니다.
또한 다른 사람들도 같은 생각을 하고 있을 경우를 대비하여 일반 사이버윈 목록에 여러분의 의도를 알려야 합니다.
6.2. 시그윈에 어떻게 기여하나요?
시그윈 자체에 기여하고 싶다면 https://cygwin.com/contrib.html 을 참조하세요.
6.3. 컴파일된 실행파일이 왜 그렇게 큰가요?!!?
기본적으로 gcc는 모든 심볼을 컴파일합니다. 또한 gcc는 유닉스에서 큰 실행 파일을 생성합니다.
이것이 신경 쓰인다면 binutils 패키지의 일부인 'strip' 프로그램을 사용하면 됩니다. 또는 -s 옵션을 사용하여 gcc로 컴파일하세요.
6.4. 애플리케이션을 64비트 시그윈으로 포팅할 때 주의해야 할 사항은 무엇인가요?
시그윈 x86_64 툴체인은 LP64 데이터 모델을 사용합니다. 즉, Linux에서와 마찬가지로 LLP64 데이터 모델인 sizeof(long) != sizeof(int)를 사용하는 윈도우와는 대조적입니다.
비교를 위해
시그윈 윈도우 시그윈
Linux x86_64 Linux
윈도우 x86_64
i686
sizeof(int) 4 4 4
sizeof(long) 4 4 8
sizeof(size_t) 4 8 8
sizeof(void*) 4 8 8
이 차이로 인해 흥미로운 문제가 발생할 수 있는데, 특히 LONG, ULONG, DWORD와 같은 윈도우 데이터 유형에 대한 포인터를 사용하는 Windows 에이피아이 함수를 사용할 때 더욱 그렇습니다. Windows가 LLP64라는 점을 감안할 때, 앞서 언급한 모든 유형은 32비트 및 64비트 Windows에서 4바이트 크기인 반면, 64비트 시그윈에서 'long'은 8바이트입니다.
ReadFile을 예로 들어보겠습니다:
ReadFile(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
32비트 시그윈 및 Mingw-w64 환경과 64비트 Mingw-w64 환경에서는 DWORD를 부호 없는 long으로 대체해도 문제가 없습니다:
부호 없는 긴 수_오브_바이트_읽기;
[...]
ReadFile (fhdl, buf, buflen, &number_of_bytes_read, NULL);
그러나 LP64를 사용하는 64비트 시그윈에서 number_of_bytes_read의 크기는 8바이트입니다. 그러나 ReadFile은 4바이트 타입에 대한 포인터를 기대하기 때문에 이 함수는 반환 시 number_of_bytes_read의 아래쪽 4바이트만 변경하고 위쪽 4바이트의 내용은 정의되지 않은 상태로 유지됩니다.
다음은 애플리케이션을 32비트 시그윈의 알려진 ILP32 데이터 모델에서 64비트 시그윈의 LP64 데이터 모델로 포팅하는 데 도움이 되는 몇 가지 참고 사항입니다. 이러한 문제는 Cygwin에만 국한된 문제가 아닙니다. AMD64 CPU가 처음 출시되었을 때 많은 Linux 애플리케이션이 데이터 유형을 다소 자유롭게 처리하는 데 어려움을 겪었습니다.
printf/scanf에서 int와 long을 혼동하지 마세요. 이
int i; long l;
printf ("%d %ld\n", l, i);
가 제대로 인쇄되지 않을 수 있습니다. 인쇄f/스캔f 함수의 유형 불일치에 대해 경고하는 gcc 옵션 -Wformat 또는 -Wall을 활성화합니다.
참고
새로운 플랫폼으로 코드를 포팅할 때뿐만 아니라 일반적으로 -Wall(선택적으로 -Werror와 함께 사용)을 사용하는 것은 매우 유용합니다.
int와 긴 포인터를 혼용하지 마세요.
long *long_ptr = (long *) &my_int; /* 이런! */
*long_ptr = 42;
이 할당은 my_int의 주소에 8바이트를 씁니다. my_int는 4바이트에 불과하기 때문에 다른 것을 무작위로 덮어쓰게 됩니다. 이런 종류의 버그를 찾는 것은 매우 어렵습니다. 실제 버그와 직접적인 관련이 없는 문제가 종종 보이기 때문입니다.
int와 포인터를 전혀 섞지 마세요! 더 이상 예상대로 작동하지 않습니다:
void *ptr;
printf ("포인터 값은 %x\n입니다.", ptr);
x는 int 인수를 나타냅니다. printf에 의해 인쇄된 값은 4바이트 값이므로 x86_64에서는 인쇄된 포인터 값에 상위 4바이트가 누락되어 출력이 잘못되었을 가능성이 매우 높습니다. 대신 아키텍처 간에 이식 가능한 %p를 사용하십시오:
void *ptr;
printf ("포인터 값은 %p\n", ptr);
같은 맥락에서 포인터 연산에 int 유형을 사용하지 마세요. 포인터를 int로 형변환하지 말고, 포인터 차이를 int로 형변환하지 말고, 포인터 차이를 int 타입에 저장하지 마세요. 대신 아키텍처에 독립적인 포인터 연산을 수행하도록 설계된 intptr_t, uintptr_t 및 ptrdiff_t 유형을 사용하세요.
POSIX 타입의 크기에 대해 맹목적으로 가정하지 마세요. 예를 들어, time_t는 long 타입을 기반으로 하기 때문에 64비트 시그윈에서는 8바이트이지만, 이 글을 쓰는 시점에서는 32비트 시그윈에서는 4바이트입니다.
선언 없이 포인터를 반환하는 함수를 사용하지 마세요. 예를 들어
printf ("오류 메시지: %s\n", strerror (errno));
문자열.h를 포함하지 않는 한 이 코드는 충돌합니다. C의 암묵적 규칙은 선언되지 않은 함수의 유형이 int라는 것입니다. 그러나 int는 4바이트이고 포인터는 8바이트이므로 printf에 주어진 문자열 포인터에는 상위 4바이트가 누락되어 있습니다.
C 기본 유형을 윈도우 에이피아이 함수와 함께 사용하지 마세요. DWORD, LONG, ULONG은 길고 부호 없는 긴 문자열과 동일하지 않다는 점에 유의하세요. 유형 문제를 방지하려면 Windows API 함수 호출과 함께 Windows 데이터 유형만 사용하세요. 위의 ReadFile 예제를 참조하세요. printf 호출의 Windows 함수도 신중하게 다루어야 합니다. 이 코드는 32비트 코드에서는 일반적이지만 64비트에서는 잘못된 값을 인쇄할 수 있습니다:
printf ("오류 메시지: %lu\n", GetLastError ());
gcc의 -Wformat 옵션을 사용하면 이에 대해 경고합니다. 이 경우 요청된 기본 유형으로 형 변환하면 도움이 됩니다:
printf ("오류 메시지: %lu\n", (부호 없는 긴) GetLastError ());
윈도우 데이터 타입과 POSIX 타입별 최소/최대 값을 혼용하지 마세요.
부호 없는 long l_max = ULONG_MAX; /* 맞습니다. */
ULONG w32_biggest = ULONG_MAX; /* 잠깐만요! 뭐야? */
ULONG w32_biggest = UINT_MAX; /* 좋아, 하지만 경계선. */
다시 말하지만, ULONG(또는 DWORD)은 부호 없는 긴 길이가 아니라 64비트에서 부호 없는 정수라는 것을 명심하세요.
6.5. 제 프로젝트가 64비트 시그윈에서 전혀 빌드되지 않습니다. 무슨 일인가요?
일반적으로 그 이유는 다음과 같습니다:
64비트 툴체인에 __CYGWIN32__가 정의되어 있지 않습니다. 이 문제는 Y2K 이전부터 존재했던 몇몇 프로젝트에서 발생할 수 있습니다. 프로젝트에서 __CYGWIN32__가 있는지 확인하고 1998년 이후 시그윈 툴체인에 정의된 __CYGWIN__로 변경하면 동일한 시그윈 관련 코드 변경을 수행할 수 있습니다.
프로젝트 관리자는 시그윈이 i686 CPU에서만 실행된다는 것을 당연하게 생각했고 코드가 이를 맹목적으로 가정하고 있습니다. 코드에 이러한 가정이 있는지 확인하고 수정해야 합니다.
프로젝트가 자동 도구를 사용 중이고 config.sub 및 config.guess 파일이 절망적으로 오래되어 x86_64-{pc,알 수 없음}-시그윈을 유효한 대상으로 인식하지 못합니다. 프로젝트 구성을 업데이트하고(기본적으로 cygport가 이 작업을 수행합니다) 다시 시도하세요.
프로젝트가 시그윈에서 윈도우 기능을 사용하는데 이전 자주 묻는 질문 항목에 설명된 문제가 발생합니다.
이 모든 경우에는 업스트림에서 수정하거나 업스트림 유지 관리자에게 패치를 보내서 향후 문제가 해결되도록 하세요.
6.6. 64비트에 대해 __CYGWIN64__가 정의되지 않은 이유는 무엇인가요?
이식 가능한 프로젝트에서 시그윈 코드를 처리하는 통일된 방법을 원하기 때문에 __CYGWIN64__가 없습니다. 시그윈32__와 __CYGWIN64__를 사용하면 아무 이유 없이 코드가 복잡해질 뿐입니다. 같은 맥락에서 Linux에서는 미리 정의된 매크로 __linux32__ 및 __linux64__를 찾을 수 없습니다.
어떤 식으로든 32비트와 64비트를 구분해야 하는 경우 세 가지 선택지가 있습니다.
코드가 CPU 아키텍처에 따라 달라지는 경우 다음과 같이 해당 아키텍처에 대해 미리 정의된 컴파일러 정의를 사용합니다:
#ifdef __CYGWIN__
# ifdef __x86_64__ /* 또는 __x86_64, __amd64__, __amd64 */.
/* AMD64 CPU 전용 코드 */.
# elif __X86__
/* ix86 CPU 전용 코드 */ # elif __X86__ /* 다른 방법
# else
# 오류 지원되지 않는 아키텍처
# endif
#endif
코드가 데이터 모델의 차이에 따라 달라지는 경우 __LP64__ 정의를 대신 사용하는 것을 고려해야 합니다:
#ifdef __CYGWIN__
# ifdef __LP64__ /* 또는 _LP64 */.
/* 64비트 CPU 전용 코드 */.
# else
/* 32비트 CPU 전용 코드 */ # else
# endif
#endif
코드에서 윈도우 함수를 사용하는데 일부 기능이 64비트 Windows 전용인 경우, windows.h를 포함하자마자 64비트 시그윈에 정의된 _WIN64를 사용하세요. 하지만 이 방법은 정말 절박한 경우에만 사용해야 하며, Windows 에이피아이 기능의 차이와 관련된 경우에만 사용해야 합니다!
#ifdef __CYGWIN__
# ifdef _WIN64
/* 64비트 윈도우 전용 코드 */.
# else
/* 32비트 윈도우 전용 코드 */ # else
# endif
#endif
6.7. glibc는 어디에 있나요?
시그윈은 glibc를 제공하지 않습니다. 대신 동일한 기능의 대부분(전부는 아님)을 제공하는 newlib를 사용합니다. glibc를 시그윈으로 포팅하는 것은 어려울 수 있습니다.
6.8. Objective C는 어디에 있나요?
Objective C 컴파일에 대한 지원은 gcc-objc 패키지에서 사용할 수 있으며, 결과 바이너리는 런타임에 libobjc2 패키지에 따라 달라집니다.
6.9. 시그윈에서 실행 오류와 함께 메이크가 실패하는 이유는 무엇인가요?
메이크파일에 이식 불가능한 셸 기능을 사용하지 않도록 주의하세요(셸 스크립트 사용의 팁 참조).
make 오류: execvp: /bin/sh: 잘못된 인수 또는 make: execvp: /bin/sh: 인자 목록이 너무 길면 윈도우 실행 모델에 비해 명령줄이 너무 길기 때문에 발생하는 경우가 많습니다. 이 문제를 해결하려면 -X 스위치를 사용하여 실행 파일의 경로를 마운트하여 해당 폴더의 모든 실행 파일에 대해 사이겍섹을 활성화하고, -x 스위치로 사이겍섹이 아닌 실행 파일도 제외해야 합니다. cygexec을 활성화하면 시그윈 실행 파일이 서로 직접 대화하므로 명령줄 제한이 증가합니다. 빈 및 /usr/bin에 대해 사이버섹을 활성화하려면 /etc/fstab에서 이러한 항목을 추가하거나 변경하면 됩니다:
C:/시그윈/bin /bin ntfs 바이너리,cygexec 0 0
C:/시그윈/bin /usr/bin ntfs 바이너리,cygexec 0 0
시그윈이 아닌 다른 프로그램을 마운트하려는 경로에 추가한 경우 다음과 같은 스크립트로 해당 프로그램을 찾을 수 있습니다:
#!/bin/sh
cd /bin; for f in `find . -형식 f -이름 '*.exe'`; do
cygcheck $f | (fgrep -qi cygwin1.dll || echo $f)
done
마운트 사용에 대한 자세한 내용은 https://cygwin.com/cygwin-ug-net/using.html#mount-table 을 참조하세요.
6.10. IPC를 사용하려면 어떻게 해야 하나요, 또는 왜 시스템 호출 오류가 발생하나요?
cygserver를 실행해 보세요. https://cygwin.com/cygwin-ug-net/using-cygserver.html 을 참조하세요. PostgreSQL을 사용하려는 경우 /usr/share/doc/시그윈/postgresql-*.README도 읽어보세요.
6.11. WinMain@16에 대한 정의되지 않은 참조가 있는 이유는 무엇인가요?
gcc를 사용하는 경우 소스 중 하나에 빈 main() 함수를 추가해 보세요. 또는 링크 명령줄에 -lm이 너무 앞쪽에 있을 수도 있습니다. 끝에 있어야 합니다:
bash$ gcc hello.c -lm
bash$ ./a.exe
Hello World!
는 작동하지만
bash$ gcc -lm hello.c
/c/TEMP/ccjLEGlU.o(.text+0x10):hello.c: `main'의 다중 정의
/usr/lib/libm.a(libcmain.o)(.text+0x0):libcmain.c: 여기에 처음 정의됨
/usr/lib/libm.a(libcmain.o)(.text+0x6a):libcmain.c: `WinMain@16'에 대한 정의되지 않은 참조
collect2: ld가 종료 상태 1을 반환했습니다.
GCJ를 사용하는 경우 "--main" 플래그를 전달해야 합니다:
gcj --main=Hello Hello.java
6.12. 윈도우 에이피아이 호출은 어떻게 사용하나요?
시그윈 도구를 사용하려면 시작 및/또는 기본 제공 코드에서 자동으로 링크되는 kernel32를 제외하고 사용하려는 윈도우 에이피아이 함수에 대한 임포트 라이브러리를 명시적으로 링크해야 합니다.
예를 들어 그래픽 함수(GDI)를 사용하려면 다음과 같이 gdi32와 링크해야 합니다:
gcc -o foo.exe foo.o bar.o -lgdi32
또는 (한 단계로 컴파일 및 링크):
gcc -o foo.exe foo.c bar.c -lgdi32
일반 설정에서는 명령줄에 -mwindows 옵션을 사용하여 user32, gdi32 및 comdlg32를 포함한 기본 라이브러리 세트를 포함할 수 있습니다(또한 프로그램을 콘솔 프로그램이 아닌 지유아이 프로그램으로 만들 수도 있습니다).
가져오기 라이브러리는 링크 줄의 마지막에 넣거나 적어도 라이브러리를 참조하는 모든 객체 파일 및 정적 라이브러리 뒤에 넣는 것이 좋습니다.
참고
윈도우 에이피아이 호출에는 몇 가지 제한 사항이 있습니다. 자세한 내용은 사용 설명서 섹션 제한된 Win32 환경 및 사용 설명서 섹션 시그윈 애플리케이션에서 Win32 파일 API 사용을 참조하세요.
6.13. 시그윈을 사용하지 않는 윈도우 실행 파일을 컴파일하려면 어떻게 해야 하나요?
mingw64-i686-gcc 및 mingw64-x86_64-gcc 패키지에서 제공하는 컴파일러는 시그윈 대신 표준 마이크로소프트 디엘엘에 대해 링크합니다. 이는 유닉스 에뮬레이션 계층이 필요 없는 네이티브 윈도우 프로그램에 적합합니다.
6.14. 런타임에 cygwin1.dll이 필요 없는 시그윈 프로그램을 빌드할 수 있나요?
아니요. 프로그램이 시그윈 에이피아이를 사용하는 경우, 실행 파일은 cygwin1.dll 없이는 실행할 수 없습니다. 특히 독립적이고 독립적인 실행 파일을 얻기 위해 시그윈 라이브러리와 정적으로 링크하는 것은 불가능합니다.
시그윈 애플리케이션을 배포하려는 경우 라이선스 옵션에 대해 설명하는 https://cygwin.com/licensing.html 을 읽고 이해하는 것이 좋습니다.
6.15. MSVCRT*.디엘엘과 cygwin1.dll을 모두 사용할 수 있나요?
아니요, 둘 중 하나만 사용해야 하며 상호 배타적입니다.
6.16. 콘솔 창을 사라지게 하려면 어떻게 해야 하나요?
컴파일 시 기본값은 콘솔 애플리케이션을 생성하는 것입니다. 지유아이 프로그램을 작성하는 경우 위에서 설명한 대로 -mwindows로 컴파일하거나 GCC 명령줄에 "-Wl,--subsystem,windows" 문자열을 추가해야 합니다.
6.17. "구분 기호 누락"에 대한 불만이 발생하는 이유는 무엇인가요?
이 문제는 일반적으로 탭 문자를 공백으로 대체하는 텍스트 편집기로 메이크파일을 편집할 때 발생합니다. 명령줄은 탭으로 시작해야 합니다. 이 문제는 시그윈에만 국한되지 않습니다.
6.18. 마이크로소프트의 윈도우 에이피아이 헤더를 재배포할 수 없는 이유는 무엇인가요?
'마이크로소프트 오픈 도구 라이선스 계약'의 하위 섹션 2.d.f에 따르면 "최종 사용자에게 재배포물을 추가로 재배포하는 것을 허용하지 않을 수 있다"고 명시되어 있는 것 같습니다. 우리는 이것을 당신에게 줄 수는 있지만 다른 사람에게 줄 수는 없다는 의미로 받아들이며, 이는 우리가 동의할 수 없는 부분입니다. 다행히도 저희는 매우 완벽한 자체 윈도우 에이피아이 헤더를 보유하고 있습니다.
6.19. 비쥬얼 스튜디오 또는 Mingw-w64에서 cygwin1.dll을 어떻게 사용하나요?
디엘엘을 동적으로 로드하려면 winsup/시그윈/how-cygtls-works.txt와 winsup/testsuite/cygload에 있는 샘플 코드를 읽고 작동 방식을 이해하세요. 짧은 버전은 다음과 같습니다:
스택 하단에 4K의 스크래치 공간이 있는지 확인합니다.
시그윈_dll_init()을 호출합니다:
HMODULE h = LoadLibrary("cygwin1.dll");
void (*init)() = GetProcAddress(h, "시그윈_dll_init");
init();
비쥬얼 스튜디오에서 정적으로 링크하려는 경우 제가 아는 한 시그윈 개발자 중 누구도 이 작업을 수행하지 않았지만 메일링 리스트에서 이 방법으로 수행 할 수 있다는 보고서를 받았습니다:
다음과 같은 방법으로 할 수 있다는 메일링 리스트의 보고가 있습니다: impdef 프로그램을 사용하여 cygwin1.dll에 대한 .def 파일을 생성합니다(소스에서 시그윈 dll을 빌드하는 경우 이미 def 파일이 있을 것입니다).
impdef cygwin1.dll > 시그윈1.def
MS VS 링커(lib)를 사용하여 가져오기 라이브러리를 생성합니다.
lib /def=시그윈1.def /out=시그윈1.lib
다음 내용으로 "my_crt0.c" 파일을 생성합니다.
#include <sys/cygwin.h>
#include <stdlib.h>
typedef int (*MainFunc) (int argc, char *argv[], char **env);
void
my_crt0 (MainFunc f)
{
시그윈_crt0(f);
}
시그윈 프롬프트에서 gcc를 사용하여 my_crt0.c를 디엘엘(예: my_crt0.dll)로 빌드합니다. 1단계와 2단계에 따라 DLL용 .def 및 .lib 파일을 생성합니다.
시그윈 웹사이트에서 crt0.c를 다운로드하여 소스에 포함시킵니다. 시그윈_crt0() 대신 my_crt0()을 호출하도록 수정합니다.
MS VC 컴파일러 cl을 사용하여 오브젝트 파일을 빌드합니다.
오브젝트 파일, 시그윈1.lib, my_crt0.lib(또는 사용자가 지정한 이름)을 실행 파일에 링크합니다.
다른 시그윈 기반 라이브러리를 사용하는 경우 gcc를 사용하여 디엘엘로 빌드한 다음 MS VC 링커를 위한 임포트 라이브러리를 생성해야 할 수 있습니다.
이 팁을 제공해주신 Alastair Growcott(alastair dot growcott at bakbone dot co dot uk)에게 감사드립니다.
6.20. .lib 파일에 어떻게 링크하나요?
.lib 파일이 C 호출 가능한 진입점이 있는 일반 정적 또는 임포트 라이브러리인 경우, 다른 *.o 파일과 마찬가지로 foo.lib를 gcc/g++용 객체 파일로 나열할 수 있습니다. 그렇지 않은 경우 다음 단계를 따르세요:
함수 테이블이 있는 C 파일을 빌드합니다. 사용하려는 모든 함수를 해당 테이블에 넣습니다. 이렇게 하면 링커가 .lib의 모든 객체 파일을 포함하도록 강제합니다. LINK.EXE가 객체 파일을 포함하도록 강제하는 옵션이 있을 수도 있습니다.
더미 'LibMain'을 빌드합니다.
필요한 모든 내보내기가 포함된 .def를 빌드합니다.
link.exe를 사용하여 .lib와 링크합니다.
또는
lib.exe를 사용하여 .lib에서 모든 오브젝트 파일을 추출합니다.
직접 호출하거나 초기화된 함수 포인터를 통해 필요한 모든 함수를 참조하는 더미 C 파일을 빌드합니다.
더미 LibMain을 빌드합니다.
모든 객체를 이 파일+LibMain과 연결합니다.
.def.
Link를 작성합니다.
이 방법을 사용하여 시그윈 개발 도구에서 MSVC(및 기타 여러 런타임 라이브러리)를 사용할 수 있습니다.
이 작업은 많은 작업(반나절 정도)이 필요하지만 사양에서 문제의 런타임 라이브러리를 다시 작성하는 것보다 훨씬 적습니다...
이 설명을 해준 Jacob Navia(root at jacob dot remcomp dot fr)에게 감사드립니다.
6.21. 시그윈을 직접 빌드하려면 어떻게 해야 하나요?
먼저 필요한 빌드 도구가 설치되어 있는지 확인해야 합니다. 최소한 gcc-g++, make, automake, autoconf, 깃, perl, gettext-devel, libiconv-devel zlib-devel, cocom 및 patch가 필요합니다.
64비트 시그윈용으로 빌드하려면 mingw64-x86_64-gcc-g++ 및 mingw64-x86_64-zlib도 필요합니다.
또한 문서를 빌드하려면 dblatex, docbook2X, docbook-xml45, docbook-xsl 및 xmlto 패키지가 필요합니다. 문서 빌드는 --disable-doc 옵션으로 구성하여 비활성화할 수 있습니다.
그런 다음 시그윈 GIT 소스 리포지토리에서 시그윈 소스를 확인합니다.) 이 방법이 소스를 가져오는 데 가장 선호되는 방법입니다. 그렇지 않으면 Cygwin 릴리스를 복제하려는 경우 해당 소스 패키지(cygwin-x.y.z-n-src.tar.bz2)를 다운로드해야 합니다.
소스와는 별도의 디렉터리에 시그윈을 빌드해야 하므로 빌드/ 디렉터리와 같은 디렉터리를 만들어야 합니다. 소스를 /oss/src/newlib-cygwin/에 체크 아웃하고 임시 위치인 /oss/install/에 설치한다고 가정하면, 시그윈을 빌드하는 데 필요한 단계는 다음과 같습니다:
mkdir -p /oss/src/newlib-cygwin/build # 빌드 디렉터리 만들기
mkdir -p /oss/install # 설치 디렉터리 만들기
$ cd /oss/src/newlib-cygwin/winsup # chdir을 시그윈 소스 디렉터리로 변경하고...
./autogen.sh # 구성 파일 생성
cd /oss/src/newlib-cygwin/build # chdir을 빌드 디렉터리로 변경합니다.
$ # 메이크파일 생성...
$ /oss/src/newlib-cygwin/configure --prefix=/oss/install
make # 빌드 시그윈
make install # 설치 디렉터리에 시그윈을 설치합니다.
빌드가 성공했다면 시그윈 디엘엘인 cygwin1.dll을 제외하고 원하는 모든 것을 현재 실행 중인 시스템에 설치할 수 있습니다. DLL을 설치하려면 모든 시그윈 프로그램(bash 창, cygserver와 같은 서버 등)을 닫고 이전 dll을 저장한 다음 새 dll을 올바른 위치에 복사합니다. 그런 다음 첫 번째 테스트를 위해 윈도우 명령 프롬프트에서 Cygwin 프로그램을 시작하고 어떤 일이 발생하는지 확인합니다.
"사용자 공유 메모리 버전 불일치가 감지되었습니다"와 같은 긴 오류 메시지가 표시되면 시그윈 프로세스가 여전히 이전 디엘엘을 사용하여 실행 중일 가능성이 높습니다. 윈도우의 작업 관리자 또는 작업 킬에서 해당 프로세스를 종료하고 다시 시도하세요. 그래도 여전히 작동하지 않고 이전 시그윈 프로세스가 여전히 실행되지 않는 것이 확실하다면 변경 사항으로 인해 버그가 발생한 것일 수 있습니다. 이제부터는 혼자서 해결하거나 Cygwin 개발자 메일링 리스트에서 문제를 논의하세요.
6.22. 시그윈에서 버그를 발견했는데 어떻게 디버깅할 수 있나요(gdb의 기호가 이상하게 보입니다)?
디버깅 심볼은 배포된 시그윈 바이너리에서 제거되므로 gdb로 디버깅하려면 cygwin-debuginfo 패키지를 설치하여 cygwin1.dll에 대한 디버그 심볼을 얻어야 합니다.
버그로 인해 cygwin1.dll 내부에서 예외가 발생하는 경우 gdb 명령 세트 cygwin-exceptions on을 사용하여 시그윈 디엘엘 내부의 예외에서 gdb가 중지하도록 지시해야 합니다(포인터가 유효한지 확인할 때와 같이 정상 작동 중에 생성될 수 있으므로 기본적으로 무시됩니다).
또한 버그가 수정된 경우 최신 코드를 사용하는 것이 좋으므로 최신 시그윈 테스트 릴리스(테스트 릴리스 설치 참조)를 시도하거나 깃에서 디엘엘을 빌드하는 것이 좋습니다.
디버깅 버전의 시그윈 디엘엘을 빌드하려면 시그윈 빌드하기의 지침을 따라야 합니다.
메일링 리스트에 연락하여 포인터를 요청할 수도 있습니다(버그를 보여주는 간단한 테스트 케이스는 언제나 환영합니다).
6.23. 지원되지 않는 플랫폼(PowerPC, 알파, ARM, 이타니움)에 대해 시그윈을 컴파일하려면 어떻게 해야 하나요?
안타깝게도 이것은 어려울 것입니다. 예외 처리 및 신호 지원 시맨틱과 인수는 x86_64용으로 설계되었으므로 플랫폼에 맞는 특정 지원 코드를 작성해야 합니다. 다른 비호환성에 대해서는 알지 못합니다. 이 작업을 수행하면 패치를 보내주세요!
6.24. 애플리케이션의 힙/스택 크기를 조정하려면 어떻게 해야 하나요?
시그윈에서 사용할 수 있는 최대 메모리 양을 변경해야 하는 경우 https://cygwin.com/cygwin-ug-net/setup-maxmem.html 을 참조하세요. 그렇지 않으면 힙/스택 링커 인수를 gcc에 전달하세요. 힙 크기가 200MB이고 스택 크기가 8MB인 foo.exe를 만들려면 다음과 같이 gcc를 호출합니다:
gcc -Wl,--heap,200000000,--stack,8000000 -o foo foo.c
6.25. 실행 파일에 필요한 디엘엘을 확인하려면 어떻게 해야 하나요?
객체 덤프 -p는 이 정보를 제공하지만 다소 장황합니다.
cygcheck는 이 작업을 훨씬 간결하게 수행하며 명령이 경로에 있는 경우 재귀적으로 작동합니다.
6.26. 디엘엘은 어떻게 빌드하나요?
시그윈 사용자 가이드에 프로세스를 설명하는 문서가 있습니다: https://cygwin.com/cygwin-ug-net/dll.html.
6.27. mainCRTStartup에서 중단점을 설정하려면 어떻게 해야 하나요?
gdb에 b *0x401000(i686의 경우) 또는 b *0x100401000(x86_64의 경우)으로 중단점을 설정합니다.
이 엔트리포인트 주소는 객관 덤프 -p로 제공된 이미지베이스 및 주소오브엔트리포인트 값의 합으로 계산할 수 있습니다.
이 중단점에 도달하기 전에 연결된 디엘엘의 DllMain 진입점이 실행되었을 것입니다.
(기본 주소가 무작위로 지정되는 것을 방지하기 위해 디버거에 대한 ASLR을 끄려면 gdb 명령으로 disable-randomization on을 설정해야 할 수도 있습니다.)
6.28. 무슨 일이 일어나고 있는지 디버깅하려면 어떻게 해야 하나요?
gdb를 사용하여 애플리케이션을 디버깅할 수 있습니다. 반드시 -g 플래그를 사용하여 컴파일하세요! 애플리케이션이 MS 디엘엘의 함수를 호출하는 경우, 프로그램을 실행할 때 gdb가 해당 함수에 대한 디버그 정보를 로드할 수 없다고 불평할 것입니다. 이러한 DLL에는 디버그 정보가 포함되어 있지 않으므로 이는 정상입니다(디버그 정보가 포함되어 있더라도 해당 디버그 정보가 gdb와 호환되지 않을 수 있습니다).
6.29. 시스템 추적 메커니즘을 대신 사용할 수 있나요?
예. strace.exe 유틸리티를 사용하여 다양한 디버그 및 추적 메시지를 활성화한 다른 시그윈 프로그램을 실행할 수 있습니다. 추적 사용에 대한 자세한 내용은 시그윈 사용자 가이드를 참조하세요.
6.30. gdb는 신호를 어떻게 처리하나요?
gdb는 알려진 윈도우 예외를 SIGSEGV, SIGFPE, SIGTRAP, SIGINT 및 SIGILL과 같은 신호에 매핑합니다. 다른 Windows 예외는 핸들러(있는 경우)로 전달되며, 처리되지 않은(두 번째 기회) 예외가 발생하면 알 수 없는 신호로 보고됩니다.
또한 SIGABRT, SIGHUP 또는 SIGUSR1과 같은 순수한 시그윈 신호를 gdb에 알리는 실험적인 기능도 있습니다. 이 기능에는 현재 알려진 몇 가지 문제가 있습니다. 예를 들어, 이러한 신호에서 한 단계씩 밟으면 예상대로 작동하지 않을 수 있습니다.
6.31. 링커가 무언가를 찾을 수 없다고 불평합니다.
일반적인 오류는 라이브러리를 필요로 하는 항목보다 먼저 명령줄에 라이브러리를 넣는 것입니다.
이것은 잘못된 gcc -lstdc++ hello.cc입니다. 올바른 명령은 다음과 같습니다.
위의 첫 번째 명령은 (일반적으로) Linux에서 작동합니다:
라이브러리 이름이 표시될 때 libstdc++에 대한 DT_NEEDED 태그가 추가됩니다.
실행 파일에 해결되지 않은 심볼이 있으며, 이 심볼은 libstdc++에서 찾을 수 있습니다.
실행되면 ELF 로더가 해당 심볼을 확인합니다.
링커 플래그 --as-needed 또는 --no-undefined가 사용되거나 링크되는 라이브러리가 정적 라이브러리인 경우 이 기능이 작동하지 않는다는 점에 유의하세요.
PE/COFF 실행 파일은 매우 다르게 작동하며, 심볼을 제공하는 동적 라이브러리는 링크 시점에 완전히 해결되어야 합니다(따라서 심볼을 제공하는 라이브러리는 해당 심볼에 대한 참조를 따라야 합니다).
이것이 플러그인에 미치는 영향에 대한 자세한 내용은 Q: 6.40의 포인트 3을 참조하세요.
이는 약한 심볼이 해결되는 방식에도 영향을 미칩니다. 이에 대한 자세한 내용은 https://cygwin.com/ml/시그윈/2010-04/msg00281.html 을 참조하세요.
6.32. 구조체 stat64를 사용하면 왜 오류가 발생하나요?
시그윈에서는 구조체 stat64를 사용하지 않고 그냥 구조체 stat를 사용합니다. 64비트를 인식합니다.
6.33. libc에 대해 링크된 디엘엘을 만들 수 있나요?
예.
6.34. malloc.h는 어디에 있나요?
존재하지만, malloc.h 대신 stdlib.h를 포함해야 합니다. stdlib.h는 malloc과 친구들을 정의하기 위한 POSIX 표준이며, malloc.h는 확실히 비표준입니다.
6.35. 나만의 malloc을 사용할 수 있나요?
자체 코드에서 malloc이라는 함수를 정의하고 디엘엘과 링크하면 DLL이 malloc을 호출합니다. 말할 필요도 없이, malloc에 버그가 있으면 심각한 문제가 발생할 수 있습니다.
bash가 아닌 도스 명령 프롬프트에서 프로그램을 실행하는 경우 디엘엘은 명령줄에서 와일드카드를 확장하려고 시도합니다. 이 프로세스는 메인 라인이 시작되기 전에 malloc을 사용합니다. 메인 라인이 호출된 후 초기화가 필요하도록 자체 malloc을 작성했다면 반드시 중단됩니다.
또한, newlib의 _malloc_r에 대한 미해결 문제가 있습니다. 이 재진입 버전은 사용자 정의 버전을 우회하여 newlib 내에서 직접 호출되며, 아마도 호환되지 않을 것입니다. 그러나 cygwin1.dll이 _malloc_r을 내보내지 않고 시그윈이 귀하의 프로그램이 이를 대체할 것으로 예상하지 않기 때문에 _malloc_r도 대체하지 못할 수 있습니다. 이것은 실제로 새로운 라이브러리 문제이지만 처리 방법에 대한 제안에 열려 있습니다.
6.36. msvc++와 gcc로 컴파일한 객체를 혼합할 수 있나요?
예, 하지만 C 오브젝트 파일을 결합하는 경우에만 가능합니다. MSVC C++는 GNU C++와 다른 망글링 체계를 사용하므로 C++ 객체를 결합하는 데 어려움이 있을 것입니다.
6.37. VC++로 빌드한 프로그램을 디버깅하기 위해 gdb 디버거를 사용할 수 있나요?
아니요, 전체(상위 수준 소스 언어) 디버깅에는 사용할 수 없습니다. 마이크로소프트 컴파일러는 다른 유형의 디버깅 심볼 정보를 생성하는데, gdb는 이를 이해하지 못합니다.
그러나 마이크로소프트 컴파일러가 생성하는 저수준(어셈블리 유형) 심볼은 gdb가 이해하는 코프입니다. 따라서 최소한 모든 전역 심볼은 볼 수 있어야 하지만 데이터 유형, 줄 번호, 로컬 변수 등에 대한 정보는 얻을 수 없습니다.
6.38. 내 메이크파일에서 셸 스크립트가 제대로 실행되지 않나요?
스크립트가 현재 디렉터리에 있는 경우 $PATH에 .(점)이 있어야 합니다. (일반적으로는 기본적으로 없습니다.) 더 좋은 방법은 메이크파일에서 호출되는 모든 셸 스크립트 앞에 /bin/sh를 추가하는 것입니다.
6.39. 어떤 전처리기 매크로에 대해 알아야 하나요?
시그윈용 gcc는 시그윈 환경용으로 빌드할 때 __CYGWIN__을 정의합니다.
마이크로소프트는 윈도우 개발 환경에서 전처리기 심볼 _WIN32를 정의합니다.
시그윈용 gcc에서 _WIN32는 -mwin32 gcc 명령줄 옵션을 사용할 때만 정의됩니다. 이는 시그윈이 애초에 POSIX 에뮬레이션 환경이어야 하며, _WIN32를 정의하면 일부 프로그램에서 Cygwin이 자동으로 처리하는 윈도우 환경을 위해 특별한 양보를 해야 한다고 생각하여 혼동을 일으키기 때문입니다.
다음과 같이 실행하여 미리 정의된 기호를 자세히 확인하십시오.
$ gcc -dM -E -xc /dev/null >gcc.txt
$ gcc -mwin32 -dM -E -xc /dev/null >gcc-mwin32.txt
그런 다음 diff 및 grep 유틸리티를 사용하여 차이점을 확인합니다.
6.40. 유닉스 지유아이를 윈도우로 포팅하려면 어떻게 해야 하나요?
다른 유닉스 계열 플랫폼과 마찬가지로 시그윈 배포판에는 X11, X Athena 위젯, Motif, Tk, GTK+, Qt 등 많은 일반적인 지유아이 툴킷이 포함되어 있습니다. 이러한 툴킷을 사용하는 많은 프로그램은 이식 가능한 경우 포팅 작업을 거의 하지 않아도 작동합니다. 하지만 몇 가지 주의해야 할 사항이 있습니다:
윈도우와 X11용으로 작성된 일부 패키지는 시그윈을 유닉스 변형이 아닌 Windows 플랫폼으로 잘못 취급합니다. 시그윈의 Unix 에이피아이와 Windows의 GDI를 혼합하는 것은 피하는 것이 가장 좋으며, 오히려 이러한 가정을 제거하여 Cygwin이 다른 X11 플랫폼처럼 취급되도록 하세요.
gtk_builder_connect_signals() 또는 glade_xml_signal_autoconnect()를 사용하는 GTK+ 프로그램은 자체적으로 dlopen()을 수행할 수 있어야 합니다. 이 기능이 작동하려면 프로그램이 -Wl,--export-all-symbols 링커 플래그와 연결되어 있어야 합니다. 이 기능은 LDFLAGS에 수동으로 추가하거나, -export-dynamic libtool 플래그(libtool 2.2.8 필요)를 사용하여 자동으로 처리하거나, 패키지를 빌드하는 데 사용되는 pkg-config 모듈에 gmodule-export-2.0을 추가하여 자동으로 처리할 수 있습니다.
자체 로드 가능한 모듈(플러그인)을 포함하는 프로그램은 종종 해당 모듈을 프로그램의 심볼에 대해 링크해야 합니다. 가장 이식성이 좋은 해결책은 이러한 프로그램이 플러그인을 링크할 수 있는 공유 라이브러리에 모든 심볼(main() 제외)을 제공하는 것입니다. 그렇지 않으면 실행 파일 자체의 심볼을 내보내야 합니다.
패키지가 CMake 빌드 시스템을 사용하는 경우 실행 파일의 set_target_properties 명령에 ENABLE_EXPORTS TRUE를 추가한 다음 실행 파일의 대상 이름을 플러그인에 대한 target_link_libraries 명령에 추가하여 이 작업을 수행할 수 있습니다.
다른 빌드 시스템의 경우 다음 단계가 필요합니다:
실행 파일은 플러그인보다 먼저 빌드해야 합니다.
실행 파일에서 -Wl,--export-all-symbols,--out-implib,libfoo.exe.a 링커 플래그를 사용하여 심볼을 내보내야 합니다(여기서 foo는 실행 파일의 이름을 나타냄).
플러그인은 -Wl,/path/to/libfoo.exe.a 링커 플래그로 연결해야 합니다.
|