콘텐츠로 건너뛰기
Home » IDE를 쓰지 않고 쪼개진 소스를 컴파일하기

IDE를 쓰지 않고 쪼개진 소스를 컴파일하기

윈도에서 Objective-C 파일을 컴파일 해보겠다고 꽤 삽질을 많이 했다. 물론 그 덕분에 컴파일러라든지 C 컴파일시에 include 파일은 어떻게 경로를 지정해서 가져오게 되는지, gcc는 사실 컴파일러와 링커를 겸한다는 것등등등 많은 공부가 된 것도 사실이다.
Dev-Cpp  등 IDE를 사용하지 않고 커맨드 창이나 Sublime Text를 사용하여 소스를 컴파일 하는 경우에는 한가지 상당히 귀찮은 문제가 발생한다. 보통 IDE에서는 헤더와 몸체 파일을 따로 만들고, 참조하고자 하는 곳에서는 헤더만 import 해서 사용하면 되는데, 이런 방식은 IDE가 제공 (make 파일을 만들어주니까)하는 방법이고, 이 방식대로라면 import 시에 헤더가 아닌 몸체 파일을 반입해야지 한 번에 컴파일이 된다.
예를 들어 연결리스트를 구현한다고 하면 (물론 파일 1개에 모두 쓸 수도 있지만) main.m 파일과 List.m, List.h 파일 Node.h, Node.m 파일… 이렇게 5개에 나눠서 소스를 정리할 수 있다. 이 때 main 파일에서는 List.h 파일만 반입해서 컴파일하는데, 이렇게 하는 것은 Xcode 등의 IDE에서 make 파일을 (실제로 Xcode는 make가 아닌 xcodeproj 파일을 사용하고 있지만) 만들어서 어떻게 컴파일 해야 하는지 알고 있기 때문이다.
만약 이런 보조적인 도구의 도움이 없다면 다음의 순서대로 컴파일해야 한다. (타이핑하기 힘들어서 그냥 OSX 기준으로)

  1. clang -c Node.m -ObjC
  2. clang -c List.m -ObjC
  3. clang -c main.m -ObjC
  4. clang main.o List.o Node.o -framework Foundation

즉 각각의 클래스에 대해서 개별적으로 컴파일 한 다음에 (gcc에 -c 옵션을 주면 오브젝트 코드를 생성하는 컴파일만 진행한다. 통상 이 옵션 없이 컴파일하면 링크까지 해서 실행 바이너리를 만들어준다.) 이렇게 생성된 모든 오브젝트 파일을 나중에 다시 하나로 합치는 것이다. (위 4번행)
아래 소스는 현재 디렉토리의 모든 파일을 검사하여 .m 으로 끝나는 파일을 Objective-C 클래스로 인식해서 모두 컴파일한다. 그런 다음, 모든 오브젝트 파일(.o)을 합쳐서 run.exe 로 만들어주는 역할을 하는 프로그램의 파운데이션 코드이다.  NSString 과  NSFileManager를 사용했으며, GNUstep에서 이들은 잘 포팅되어 정상적으로 작동하는 것을 확인할 수 있다.(GNUStep은 기본 위치인 C:\GNUstep에 설치하였으며, Clang도 C:\clang에 들어있다고 가정한다.)


#import <Foundation/Foundation.h>
void compile(NSString *filepath)
{
NSString *cmd = [NSString stringWithFormat:@"c:/clang/bin/clang.exe -c %@ -ObjC -I c:/GNUstep/GNUstep/System/Library/Headers -I c:/GNUstep/include", filepath];
system([cmd UTF8String]);
}
void linkFiles(NSArray *objects, NSString *output)
{
NSString *files = @"";
for (id i in objects)
{
files = (NSString*)[files stringByAppendingFormat:@" %@", i];
}
NSString *cmd = [NSString stringWithFormat:@"c:/clang/bin/clang %@ -o %@ -Objc -L C:/GNUstep/GNUstep/System/Library/Libraries -lobjc -lgnustep-base", files, output];
system([cmd UTF8String]);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableArray *objectFiles = [NSMutableArray array];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *curdir = [fileManager currentDirectoryPath];
NSError *error = nil;
NSArray *arr = [fileManager contentsOfDirectoryAtPath:curdir error:&error];
// complie m files
for (id i in arr)
{
if([[(NSString*)i pathExtension] isEqualToString:@"m"]) {
NSLog(@"Compile : %@", i);
NSString *fullpath = [curdir stringByAppendingPathComponent:i];
compile(fullpath);
}
}
// find All object files
arr = [fileManager contentsOfDirectoryAtPath:curdir error:&error];
for (id i in arr)
{
if( [[(NSString*)i pathExtension] isEqualToString:@"o"]) {
[objectFiles addObject:i];
}
}
NSString *oName = (argc > 1) ? [NSString stringWithUTF8String:argv[1]] : @"run" ;
if([objectFiles count]) linkFiles(objectFiles, oName);
}
return 0;
}

view raw

scc.m

hosted with ❤ by GitHub