Используйте один и тот же файл makefile для make (Linux) и nmake (Windows)

у меня есть простая C-программа (1 исходный файл), которую я хочу скомпилировать в Linux и Windows через make resp. программа NMAKE. Есть ли возможность выполнить это с помощью одного файла makefile?

Я думал о чем-то вроде

ifeq($(MAKE), nmake)
    // nmake code here
else
    // make code here
endif

к сожалению, nmake, кажется, не понимает ifeq, поэтому я не могу использовать это. У меня есть рабочий makefile, но это дает очень уродливые результаты:

hello: hello.c
    $(CC) hello.c

это работает на обеих системах. Проблема в том, что результат зависит от поведения по умолчанию соответствующих компиляторов. Под Linux я получаю исполняемое имя "a".из", а не "привет". Под окнами я получаю "привет".exe а также Здравствуйте.возражение, которого я не хочу иметь.

кто-нибудь знает альтернативный способ? Или то, что я пытаюсь сделать, абсолютно невозможно?

6 ответов


Это, вероятно, не невозможно, но, скорее всего, так сложно, что было бы проще написать два файла Makefile в любом случае.

как GNU make (используется в Linux), так и nmake имеют директивы include, поэтому некоторые общие вещи могут быть помещены в общий файл makefile, который включен в основной файл makefile.


вы должны смотреть на использование CMake для этого. С одним исходным файлом это должно быть довольно просто!

EDIT:

вот как вы могли бы настроить простой проект:

cmake_minimum_required(VERSION 2.8)

project(Simple)

include_directories("${PROJECT_BINARY_DIR}")

add_executable(Simple simple.cpp)

чтобы построить простой проект, вы должны сделать следующее (Это предполагает ваш источник и CMakeLists.txt файлы в ~/src/simple:

foo@bar~/src/simple$ mkdir build
foo@bar~/src/simple$ cd build
foo@bar~/src/simple$ cmake ..
foo@bar~/src/simple$ make

Я хотел использовать тот же файл makefile include для использования make и nmake. Поскольку make распознает продолжение строки в строках комментариев, а nmake-нет, это означает, что у нас могут быть отдельные инструкции для make и nmake. например:

# \
!ifndef 0 # \
# nmake code here \
MV=move # \
RM=del # \
CP=copy # \
!else
# make code here
MV=mv -f
RM=rm -f
CP=cp -f
# \
!endif

просто убедитесь, что конкретный код nmake завершается # \


Я не могу найти способ использовать общий файл makefile для работы как для GNU make, так и для MS nmake, главным образом потому, что у них есть несовместимый синтаксис для директив "include" и/или "if". MS nmake требует использования ! префикс для директив. например !если !включать и т. д...

если разрешено иметь отдельные макросы, однако, его можно обмануть. Здесь я представляю лучший способ, который я нашел до сих пор для совместимости makefile как для GNU make, так и для MS nmake, наблюдая за следующими:

  1. MS nmake считывает инструменты.ini-файл для макросов по умолчанию.
  2. MS suite использует .obj как расширение файла объекта.
  3. GNU make считывает файлы, определенные в переменной среды MAKEFILES.
  4. использование GNU suite .o как расширение файла объекта.
  5. GNU make не нужно давать исполняемое расширение .exe для цели.

Примечание: следующее было протестировано с помощью MS 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: Создайте инструменты.файл 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: Создайте инструменты.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)), где указаны только dependecies.

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: наслаждайтесь GNU make и MS nmake с тем же makefile

$ nmake
$ make clean
$ nmake clean
$ make

Я просто думал о чем-то совершенно другом.

если вы придерживаетесь своего чрезвычайно простого файла Makefile, который, как вы говорите, работает, и просто помещаете "стандартные" переменные CC и CFLAGS в соответствующие среды, скажем

  export CC=gcc

соответственно

  set CC=CL.EXE

и

  export CFLAGS=-o myexecutable

соответственно

  set CFLAGS=/out:myexecutable.exe

это может сработать.

имейте в виду, я не тверд в точных вариантах использования, вам придется их выяснить себе. Но AFAIK оба варианта распознают один и тот же набор флагов. Вы даже можете установить их в соответствующих командных строках (но не в файле makefile, так как NMAKE использует другой синтаксис "ifeq"...)


Да, вы можете сделать это с помощью одного из Makefile. Лучший источник этого материала-книга О'Рейли:--2-->

Управление проектами с GNU Make, третье издание Роберта Мекленбурга

см. Главу 7: переносные файлы Makefile.

В общем, метод состоит в том, чтобы проверить переменную среды ComSpec, которая говорит, если присутствует интерпретатор команд windows:

ifdef COMSPEC
 MV ?= move
 RM ?= del
else
 MV ?= mv -f
 RM ?= rm -f
endif

Я обертываю это с помощью портативного скрипта оболочки, который использует sed для отредактируйте файл makefile для Nmake или Gnu-make..