make (Linux)와 nmake (Windows)에 동일한 make 파일 사용
저는 make와 nmake를 통해 리눅스와 윈도우에서 각각 컴파일하고 싶은 간단한 C 프로그램(소스 파일 하나)이 있습니다.메이크 파일 하나로 가능성이 있습니까?
이런 생각을 해봤는데요.
ifeq($(MAKE), nmake)
// nmake code here
else
// make code here
endif
안타깝게도 nmake는 이해하지 못하는 것 같습니다.ifeq
, 그래서 저는 그걸 사용할 수 없습니다.작동하는 makefile을 가지고 있지만 결과가 매우 좋지 않습니다.
hello: hello.c
$(CC) hello.c
두 시스템 모두에서 작동합니다.문제는 각 컴파일러의 기본 동작에 따라 결과가 달라진다는 것입니다.리눅스에서 나는 'hello'가 아닌 'a.out'이라는 이름의 실행 파일을 받습니다.윈도우에서는 'hello.exe'가 나오지만 제가 갖고 싶지 않은 'hello.obj'도 있습니다.
다른 방법이 있습니까?아니면 내가 시도하는 것은 절대 불가능한 것입니까?
불가능한 것은 아니지만 너무 어려워서 어쨌든 두 개의 메이크 파일을 작성하는 것이 더 쉬울 것입니다.
GNU make(리눅스에서 사용되는)와 nmake 모두 지시어를 포함하고 있기 때문에 몇 가지 일반적인 것들은 메인 makefile에 포함된 공통 makefile에 넣을 수 있습니다.
이것은 CMake를 사용하는 것을 고려해야 합니다.소스 파일 하나면 꽤 쉬울 겁니다.간단한 프로젝트를 설정하는 방법은 다음과 같습니다.
cmake_minimum_required(VERSION 3.10)
# set the project name
project(Hello)
# add the executable
add_executable(Hello hello.c)
간단한 프로젝트를 구축하기 위해 다음과 같은 작업을 수행합니다(소스 및 CMakeLists를 가정합니다). 파일 txt 파일과 .hello.c
:
mkdir build
cd build
cmake ..
cmake --build .
Make와 NMAKE에서 사용하는 것과 같은 make file include를 사용하고 싶었습니다.make는 continuation을 댓글 라인에서는 인식하지만 NMAKE는 인식하지 않기 때문에 Make와 NMAKE에 대한 별도의 지시사항을 가질 수 있습니다.예를 들어,
# NMAKE code here \
!ifndef 0 # \
MV=move # \
RM=del # \
CP=copy # \
!else
# Make code here
MV=mv -f
RM=rm -f
CP=cp -f
# \
!endif
NMAKE 가 NMAKE 의 되는지 하면 에 포함되는지 .# \
.
주로 "include" 및/또는 "if" 명령어에 대해 호환되지 않는 구문을 가지고 있기 때문에 GNU Make와 Microsoft NMAKE 모두에서 작동하기 위해 공통 makefile을 사용할 방법을 찾을 수 없습니다.Microsoft NMAKE는 지시어에 ! 접두사를 사용해야 합니다.예를 들어 !if, !include 등이 있습니다.
그러나 별도의 매크로를 허용하면 속을 수 있습니다.여기서 저는 다음을 관찰함으로써 GNU Make와 Microsoft NMAKE 모두에 호환되는 makefile을 만들기 위해 지금까지 찾은 최선의 방법을 제시합니다.
- Microsoft NMAKE는 기본 매크로에 대해 TOOLS.ini 파일을 읽습니다.
- 마이크로소프트 제품군은 .obj를 개체 파일 확장명으로 사용합니다.
- GNU Make는 MAKEFILES 환경 변수에 정의된 파일을 읽습니다.
- GNU 제품군은 .o를 개체 파일 확장자로 사용합니다.
- GNU make는 대상에 대해 실행 파일 확장자 .exe를 제공할 필요가 없습니다.
참고: Microsoft Visual Studio 2015 및 MINGW32를 사용하여 테스트한 내용은 다음과 같습니다.
1단계: 다음 DOS 배치 파일을 만들고 CMD 프롬프트가 호출될 때마다 실행되도록 합니다.
set MAKEFILES=TOOLS.gcc
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
2단계: 다음과 같이 작업 디렉토리 아래에 TOOLS.ini 파일을 만듭니다. (이 파일은 라이브러리를 제외하고 프로젝트 종속성과는 무관합니다.)
[NMAKE]
LDLIBS =
CDEBUG = /Zi
LDEBUG = /debug:full
WDFLAGS = /wd4996 /wd4774 /wd4018 /wd4710 /wd4820
CFLAGS = /nologo $(CDEBUG) /EHsc /Wall $(WDFLAGS)
LDFLAGS = /nologo $(LDEBUG)
RM = del /F /Q
LINK = "$(VCINSTALLDIR)bin\link" $(LDFLAGS)
CP = copy
CC = cl
CPP = $(CC) /P
X = .exe
O = .obj
.obj.exe:
$(LINK) $** $(LOADLIBES) $(LDLIBS) /Out:$@
3단계: 아래와 같이 작업 디렉토리 아래에 TOOLS.gcc를 만듭니다. (이 파일은 라이브러리를 제외하고 프로젝트 종속성과는 무관합니다.)
LD_LIBS =
LDLIBS =
CDEBUG = -g
LDEBUG = -g
CFLAGS = $(CDEBUG)
LDFLAGS = $(LDEBUG)
RM = rm -f
LINK = gcc $(LDFLAGS)
CP = cp
CC = gcc
CPP = $(CC) -E
X =
O = .o
%: %.o
$(LINK) $^ $(LOADLIBES) $(LDLIBS) -o $@
4단계: 종속성만 지정된 makefile을 아래와 같이 편집합니다($X) 및 $(O).
SHELL = /usr/bin/sh
app: app1$(X) app2$(X)
app1$(X): app1$(O)
app2$(X): app2$(O)
clean:
$(RM) *.exe *.o *.obj *.ilk *.pdb *.tmp *.i *~
5단계: 동일한 makefile로 GNU Make와 Microsoft NMAKE 즐기기
$ nmake
$ make clean
$ nmake clean
$ make
제 해결책은 두 개의 다른 파일 이름을 사용하는 것입니다.(다른 OS에서 Makefile name 검색 우선순위가 같지 않기 때문에)
Windows의 경우 일반 "Makefile"을 사용합니다.
리눅스의 경우 이 기사에 따라 특별한 "GNUmakefile"을 사용합니다.
그래서 nmake (Win)은 "Makefile"을, make (Linux)는 "GNUmakefile"을 찾을 것입니다.
해결책: https://github.com/jaykrell/w3/blob/master/Makefile
# This one Makefile works with Microsoft nmake and GNU make.
# They use different conditional syntax, but each can be
# nested and inverted within the other.
all: default
ifdef MAKEDIR: # gmake: false; nmake: unused target
!ifdef MAKEDIR # gmake: not seen; nmake: true
#
# Microsoft nmake.
#
!else # and now the other
else
#
# GNU (Posix?) make.
#
endif # gmake: close condition; nmake: not seen
!endif : # gmake: unused target; nmake close conditional
default: # default target for both
저는 그냥 완전히 다른 생각을 했어요.
매우 단순한 Makefile을 고수하고 '표준' 변수 CC와 CFLAGS를 각자의 환경에 배치한다면,
export CC=gcc
각각 다음과 같다.
set CC=CL.EXE
그리고.
export CFLAGS=-o myexecutable
각각 다음과 같다.
set CFLAGS=/out:myexecutable.exe
효과가 있을지도 모릅니다.
제가 정확한 사용 방법에 대해 잘 모르니, 직접 생각해 보셔야 합니다.그러나 AFAIK는 둘 다 변종들이 동일한 플래그 집합을 인식하도록 합니다.각각의 명령줄에서 설정할 수도 있습니다(그러나 makefile에서는 설정할 수 없습니다. NMAKE는 다른 'ifeq' 구문을 사용하기 때문에...).
예, 이것은 메이크 파일 하나로 할 수 있습니다.이 자료에 가장 적합한 자료는 오라일리 책입니다.
Robert Mecklenburg의 GNU Make, Third Edition으로 프로젝트 관리
7장: 휴대용 파일 만들기를 참조하십시오.
요약하면, 이 기법은 환경 변수 ComSpec을 테스트하는 것으로, Windows 명령 인터프리터가 존재하는 경우 다음과 같이 말합니다.
ifdef COMSPEC
MV ?= move
RM ?= del
else
MV ?= mv -f
RM ?= rm -f
endif
나는 이것을 Nmake나 GNU make의 makefile을 편집하기 위해 sed를 사용하는 휴대용 셸 스크립트로 포장합니다.
저는 최근에 C 전처리기를 사용하여 전처리기 기호가 포함된 템플릿 Makefile.cc 에서 휴대용 Makefile을 생성하는 실험을 했습니다.지금까지는 놀라울 정도로 잘 작동했습니다.첫번째 관찰은 NMAKE가 다음과 같은 디렉토리에서 제공하는 Tools.ini 파일을 prescan 할 것이라는 것입니다.
[NMAKE]
MAKECONFIG=-D_NMAKE
그러면 옆에 GNU Make와 NMAKE의 공통 하위 언어로만 작성된 'true' Make 파일이 있습니다.
MAKEFILE=Makefile.mk
TEMPLATE=Makefile.cc
all: $(MAKEFILE)
$(MAKE) -f $(MAKEFILE)
clean: $(MAKEFILE)
$(MAKE) -f $(MAKEFILE) clean
$(MAKEFILE): $(TEMPLATE)
$(CXX) $(MAKECONFIG) -E $(TEMPLATE) > $(MAKEFILE)
-E 스위치는 파일을 사전 처리하기 위한 컴파일러(적어도 제가 작업하는 빅 3: GCC, Clang, CL)에 꽤 흔합니다.GNU Make $(MAKECONFIG)를 사용하면 $(MAKECONFIG)이 아무것도 아닌 것으로 확장되지만 NMAKE에서는 자체를 선언하는 전처리기 변수를 제공합니다.Makefile.cc 템플릿은 #ifdef로 확인할 수 있을 뿐만 아니라 컴파일러가 선언하는 일반적인 변수도 확인할 수 있으므로 'make' 프로그램, 운영 체제 및 사용 중인 컴파일러 모두에 대해 Makefile.mk 을 사용자 지정할 수 있습니다.
'만들 수 있는' 것이 있다면 아마 C 컴파일러도 이미 가지고 있을 것입니다. CMake나 오토툴과 같은 추가 소프트웨어를 설치할 필요가 없습니다.그것은 오래되어 여러 환경에서 작동할 가능성이 높은 메커니즘을 사용합니다.그리고 지금까지 제가 알 수 있었던 것으로 미루어 봤을 때, 그것은 정말 빠릅니다.최소한 자동 도구에서 구성 단계를 실행하는 것보다 빠릅니다.제가 직면한 유일한 단점은 이것이 당신의 만들기 규칙의 스타일을 동일한 줄에 있는 것으로 제한한다는 것입니다. 왜냐하면 전처리기가 코드의 들여쓰기를 바꾸기 때문입니다.또한 전처리기는 # 태그로 행을 표시하지만, 이것들은 Makefile에서 주석을 시작하기 때문에 어쨌든 무시됩니다.
A는 다음 토막글처럼 보이는 Makefile.cc 을 가진 다소 작은 C++ 프로젝트를 가지고 있습니다.GCC, Clang, CL 중 하나와 윈도우 또는 POSIX 환경에서 GNU Make 또는 NMAKE를 컴파일합니다.BSD Make나 다른 컴파일러 테스트는 아직 지원하지 않았습니다.
// Make Version
#ifdef _NMAKE
# define ifdef !ifdef
# define ifndef !ifndef
# define else !else
# define endif !endif
# define err(x) !error x
# define cat(x, y) x=$(x) y
#else // GNU Make
# define err(x) $(error x)
# define cat(x, y) x += y
#endif
// System Commands
ifdef SHELL
RM=rm -f
else
ifdef COMSPEC
RM=del /f
else
err("Cannot determine your system commands.")
endif // COMSPEC
endif // SHELL
// Project Variables
STD=c++17
SRC=test.cpp dbg.cpp dir.cpp dll.cpp env.cpp err.cpp fifo.cpp file.cpp shm.cpp sig.cpp socket.cpp sys.cpp xdg.cpp
BIN=test
.SUFFIXES: .cpp .hpp .o .d .obj .pdb .lib .exp .ilk .log .i .db
// Operating system
#ifdef _WIN32
cat(CFLAGS, -D_WIN32)
EXE=$(BIN).exe
#else
cat(CFLAGS, -D_POSIX_C_SOURCE)
cat(LDFLAGS, -ldl -lrt -lpthread)
EXE=$(BIN)
#endif
// Make Targets
all: $(EXE)
clean: ; $(RM) $(EXE) *.o *.d *.obj *.pdb *.lib *.exp *.ilk *.log *.i
// Compiler Options
#ifdef _MSC_VER
cat(CFLAGS, -nologo -std:$(STD) -W4 -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -EHsc -permissive-)
ifndef NDEBUG
cat(CFLAGS, -Zi)
endif
cat(LDFLAGS, -nologo)
OBJ=$(SRC:.cpp=.obj)
$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -Fe$@
.cpp.obj: ; $(CXX) $(CFLAGS) -c $<
#elif defined(__GNUC__) || defined(__llvm__) || defined(__clang__)
cat(CFLAGS, -std=$(STD) -Wall -Wextra -Wpedantic -MP -MMD)
ifndef NDEBUG
cat(CFALGS, -g)
endif
cat(LDFLAGS, -rdynamic)
OBJ=$(SRC:.cpp=.o)
$(EXE): $(OBJ); $(CXX) $(LDFLAGS) $(OBJ) -o $@
.cpp.o: ; $(CXX) $(CFLAGS) -c $<
# ifndef _NMAKE
-include $(SRC:.cpp=.d)
# endif
#else
# error "Cannot determine your compiler."
#endif
gnused 또는 perl로 된 스크립트를 사용하여 호스트의 Make 파일을 Microsoft 호환 NMake 파일로 변환할 수 있지 않을까요?만들기 파일은 결국 사용 중인 도우미 도구에 대한 입력을 제공하기 위한 텍스트 파일입니다.리눅스와 윈도우용으로 Sed와 Perl이 둘 다 존재합니다.
언급URL : https://stackoverflow.com/questions/8270391/use-the-same-makefile-for-make-linux-and-nmake-windows
'programing' 카테고리의 다른 글
Spring REST 컨트롤러에서 HTTP 헤더 읽기 (0) | 2023.09.18 |
---|---|
MariaDB: 세미콜론으로 구분된 문자열을 분할하여 평균값 계산 (0) | 2023.09.18 |
연락처 양식 7 - php 실행 불가 (0) | 2023.09.18 |
활성 시트.사용 범위.기둥.카운트 - 8 그게 무슨 뜻입니까? (0) | 2023.09.18 |
Android 소프트키보드가 보일 때 전체 화면 모드에서 레이아웃을 조정하는 방법 (0) | 2023.09.18 |