【问题标题】:Cannot compile Makefile using make command on Windows无法在 Windows 上使用 make 命令编译 Makefile
【发布时间】:2021-11-23 19:34:15
【问题描述】:

问题总结

我正在尝试安装名为 TACS 的开源并行有限元代码,可在 this github repository 获得。为了满足指定的先决条件,我按照this github repository 的说明进行操作,这使我可以在 Windows 上安装 SuiteSparseMETIS 并使用预编译的 BLAS/LAPACK DLL。对于 MPI,我通过 Cygwin 安装了 Intel MPI Library 和 Open MPI。最后一步应该是编译运行make,但是此命令在 Windows 10 中不直接可用。因此,我探索了this question 中建议的选项,不幸的是没有成功。我觉得死路一条,任何帮助将不胜感激。

我尝试过的

请看下面我的尝试。我主要是 Windows 用户,我不太了解使用 Makefile 编译程序。我目前的理解是,我试图编译的Makefile 是为 Linux 编写的,而我使用的任何 Windows GNU 编译器都无法工作,因为需要不同的语法。如果我错了,请纠正我。我无法理解的是为什么当我尝试使用适用于 Windows 10 的 Ubuntu Bash 进行编译时也会出现错误(下面列表的最后一次尝试)。

Visual Studio nmake

以管理员身份运行 VS 2019 的开发人员命令提示符,我在 TACS 基本目录中输入了nmake -f Makefile,得到了Makefile.in(28) : fatal error U1001: syntax error : illegal character '{' in macro Stop.

巧克力make

以管理员身份运行 Windows 命令提示符,C:\ProgramData\chocolatey\binPATH 环境变量的顶部,我在 TACS 基本目录中输入了 make,我得到了

"" was unexpected at this time.
make: *** [Makefile:23: default] Error 255

赛格温make

以管理员身份运行 Windows 命令提示符,C:\cygwin64\binPATH 环境变量的顶部,我在 TACS 基本目录中输入了make,我得到了三种类型的错误:

error: expected ',' or '...' before numeric constant
error: cannot convert 'int*' to 'idx_t*' {aka 'long int*'}
error: no matching function for call to 'TACSSchurMat::getBCSRMat(BCSRMat**, NULL, NULL, NULL)'

我尝试更改受影响脚本中的一些变量名称(例如 N_ 代替 _N),我摆脱了第一种和第三种类型的错误,但没有消除第二种错误。

GnuWin make

以管理员身份运行 Windows 命令提示符,C:\Program Files (x86)\GnuWin32\binPATH 环境变量的顶部,我在 TACS 基本目录中输入了 make,我得到了

"" was unexpected at this time.
make: *** [Makefile:23: default] Error 255

MinGWmingw32-make

以管理员身份运行 Windows 命令提示符,C:\MinGW\binPATH 环境变量的顶部,我在 TACS 基本目录中输入了 mingw32-make,然后我得到了

"" was unexpected at this time.
Makefile:23: recipe for target 'default' failed
mingw32-make: *** [default] Error 255

MSYS MinGW 64 位 make

以管理员身份运行 Windows 命令提示符,C:\msys64\usr\binPATH 环境变量的顶部,我在 TACS 基本目录中输入了 make,我得到了

make[1]: mpicxx: No such file or directory
make[1]: *** [../TACS_Common.mk:28: C:/Users/qa21944/git/tacs/src/TACSAssembler.o] Error 127
make[1]: *** Waiting for unfinished jobs....
make[1]: mpicxx: No such file or directory
make[1]: *** [../TACS_Common.mk:28: C:/Users/qa21944/git/tacs/src/TACSCreator.o] Error 127
make[1]: Leaving directory '/c/Users/qa21944/git/tacs/src'
make: *** [Makefile:23: default] Error 1

这对我来说很难理解,因为mpicxx 文件是C:\Program Files (x86)\Intel\oneAPI\mpi\latest\bin,而它又位于PATH 环境变量中。当我尝试将C:\cygwin64\bin 添加到PATH(低于C:\msys64\usr\bin)并重新运行make 时,我得到了

      0 [main] opal_wrapper (14432) C:\cygwin64\bin\opal_wrapper.exe: *** fatal error - cygheap base mismatch detected - 0x180352408/0x180357408.
This problem is probably due to using incompatible versions of the cygwin DLL.
Search for cygwin1.dll using the Windows Start->Find/Search facility
and delete all but the most recent version.  The most recent version *should*
reside in x:\cygwin\bin, where 'x' is the drive on which you have
installed the cygwin distribution.  Rebooting is also suggested if you
are unable to find another cygwin DLL.

我尝试按照这些说明进行操作,然后重新启动计算机,但没有任何改变。

适用于 Windows 10 的 Ubuntu Bash make

这次尝试的灵感来自this answer。我从 Microsoft Store 下载了 Ubuntu 并安装了 make。在 Ubuntu Bash 中,我在 TACS 基本目录中输入了make,然后我得到了

make[1]: Entering directory '/mnt/c/Users/qa21944/git/tacs/src'
Makefile:26: *** target pattern contains no '%'.  Stop.
make[1]: Leaving directory '/mnt/c/Users/qa21944/git/tacs/src'
make: *** [Makefile:23: default] Error 1 

我不明白为什么会出现此错误。我还确保所有行都以制表符而不是空格开头,但没有任何改变。

代码

您可以在下面找到我正在使用的Makefile.inMakefile

Makefile.in

# Do not modify this file. Copy this file to Makefile.in and then modify it.

# In order to get TACS to compile, you'll need to fill in the
# following path information. Some of the items below are required
# only if you're going to use the python interface.

# the full path to the root TACS directory
TACS_DIR = C:/Users/qa21944/git/tacs
CXX = mpicxx
RM = rm -f
PYTHON = python
PYTHON_CONFIG = python-config

# Set up for parallel make
MAKE = make -j 8

# Set the ar flags
AR_FLAGS = rcs

# Flags for debugging and regular compilation versions
EXTRA_DEBUG_CC_FLAGS = -fPIC -g 
EXTRA_CC_FLAGS = -fPIC -O3

# Use this if you have problems with mpich
# TACS_DEF = -DMPICH_IGNORE_CXX_SEEK

# Defines whether to use static or dynamic linking
# TACS_LD_CMD=${TACS_DIR}/lib/libtacs.a
TACS_LD_CMD=-L${TACS_DIR}/lib/ -Wl,-rpath,${TACS_DIR}/lib -ltacs

# For linux systems, use the following settings:
SO_EXT=so
SO_LINK_FLAGS=-fPIC -shared

# For MAC OS X, use the following settings:
# SO_EXT=so
# SO_LINK_FLAGS=-fPIC -dynamiclib

# This uses the default installation of LAPACK. 
# Use an optimized version of LAPACK if available.
# You may also have to include -lblas as well.

LAPACK_LIBS = -LC:/SP_ROOT/lapack_windows/x64 -llapack -lpthread -lblas

# For MAC OSX use the accelerate framework
# LAPACK_LIBS=-framework accelerate

# METIS is handy for partitioning graphs, but can be problematic for
# compilation.  If you compile METIS using a C++ compiler you must add
# -DTACS_CPLUSPLUS_METIS to the TACS_DEF arguments below. If you
# compile METIS using a C compiler, there should be no issues.

METIS_INCLUDE = -IC:/SP_ROOT/build/install/include
METIS_LIB = -LC:/SP_ROOT/build/install/lib -lmetis

# AMD is a set of routines for ordering matrices. It is not required by default.

AMD_INCLUDE = -IC:/SP_ROOT/build/install/include/suitesparse
AMD_LIBS = -LC:/SP_ROOT/build/install/lib -llibamd

生成文件

# ============================================
#
# Make file for TACS_DIR/
#
# ============================================

include Makefile.in
include TACS_Common.mk

TACS_SUBDIRS = src \
    src/bpmat \
    src/elements \
    src/elements/dynamics \
    src/elements/basis \
    src/elements/shell \
    src/constitutive \
    src/functions \
    src/io

TACS_OBJS := $(addsuffix /*.o, ${TACS_SUBDIRS})

default:
    @if [ "${TACS_IS_COMPLEX}" = "true" ]; then \
       echo "Building Complex TACS"; \
       for subdir in $(TACS_SUBDIRS) ; do \
          echo "making $@ in $$subdir"; \
          echo; (cd $$subdir && $(MAKE) TACS_DIR=${TACS_DIR} TACS_DEF="${TACS_DEF} -DTACS_USE_COMPLEX") || exit 1; \
            done \
    else \
       echo "Building Real TACS"; \
       for subdir in $(TACS_SUBDIRS) ; do \
          echo "making $@ in $$subdir"; \
          echo; (cd $$subdir && $(MAKE) TACS_DIR=${TACS_DIR}) || exit 1; \
            done \
    fi
    ${CXX} ${SO_LINK_FLAGS} ${TACS_OBJS} ${TACS_EXTERN_LIBS} -o ${TACS_DIR}/lib/libtacs.${SO_EXT}
    @if [ "${TACS_IS_COMPLEX}" = "true" ]; then \
        echo "ctypedef complex TacsScalar" > tacs/TacsTypedefs.pxi; \
        echo "TACS_NPY_SCALAR = np.NPY_CDOUBLE" > tacs/TacsDefs.pxi; \
        echo "dtype = complex" >> tacs/TacsDefs.pxi; \
    else \
        echo "ctypedef double TacsScalar" > tacs/TacsTypedefs.pxi; \
        echo "TACS_NPY_SCALAR = np.NPY_DOUBLE" > tacs/TacsDefs.pxi; \
        echo "dtype = np.double" >> tacs/TacsDefs.pxi; \
    fi

debug:
    @if [ "${TACS_IS_COMPLEX}" = "true" ]; then \
       echo "Building Complex TACS"; \
       for subdir in $(TACS_SUBDIRS) ; do \
          echo "making $@ in $$subdir"; \
          echo; (cd $$subdir && $(MAKE) debug TACS_DIR=${TACS_DIR} TACS_DEF="${TACS_DEF} -DTACS_USE_COMPLEX") || exit 1; \
            done \
    else \
       echo "Building Real TACS"; \
       for subdir in $(TACS_SUBDIRS) ; do \
          echo "making $@ in $$subdir"; \
          echo; (cd $$subdir && $(MAKE) debug TACS_DIR=${TACS_DIR}) || exit 1; \
            done \
    fi
    ${CXX} ${SO_LINK_FLAGS} ${TACS_OBJS} ${TACS_EXTERN_LIBS} -o ${TACS_DIR}/lib/libtacs.${SO_EXT}
    @if [ "${TACS_IS_COMPLEX}" = "true" ]; then \
        echo "ctypedef complex TacsScalar" > tacs/TacsTypedefs.pxi; \
        echo "TACS_NPY_SCALAR = np.NPY_CDOUBLE" > tacs/TacsDefs.pxi; \
        echo "dtype = complex" >> tacs/TacsDefs.pxi; \
    else \
        echo "ctypedef double TacsScalar" > tacs/TacsTypedefs.pxi; \
        echo "TACS_NPY_SCALAR = np.NPY_DOUBLE" > tacs/TacsDefs.pxi; \
        echo "dtype = np.double" >> tacs/TacsDefs.pxi; \
    fi

interface:
    ${PYTHON} setup.py build_ext --inplace

complex_interface:
    ${PYTHON} setup.py build_ext --inplace --define TACS_USE_COMPLEX

complex: TACS_IS_COMPLEX=true
complex: default

complex_debug: TACS_IS_COMPLEX=true
complex_debug: debug

clean:
    ${RM} lib/libtacs.a lib/libtacs.so
    ${RM} tacs/*.so tacs/*.cpp
    @for subdir in $(TACS_SUBDIRS) ; do \
      echo "making $@ in $$subdir"; \
      echo; \
         (cd $$subdir && $(MAKE) $@ TACS_DIR=${TACS_DIR}) || exit 1; \
    done

编辑:我正在根据 cmets 的要求添加一个TACS_Common.mk 的 sn-p。

TACS_Common.mk

TACS_LIB = ${TACS_DIR}/lib/libtacs.a

TACS_INCLUDE = -I${TACS_DIR}/src \
    -I${TACS_DIR}/src/bpmat \
    -I${TACS_DIR}/src/elements \
    -I${TACS_DIR}/src/elements/dynamics \
    -I${TACS_DIR}/src/elements/basis \
    -I${TACS_DIR}/src/elements/shell \
    -I${TACS_DIR}/src/constitutive \
    -I${TACS_DIR}/src/functions \
    -I${TACS_DIR}/src/io

# Set the command line flags to use for compilation
TACS_OPT_CC_FLAGS = ${TACS_DEF} ${EXTRA_CC_FLAGS} ${METIS_INCLUDE} ${AMD_INCLUDE} ${TACS_INCLUDE}
TACS_DEBUG_CC_FLAGS = ${TACS_DEF} ${EXTRA_DEBUG_CC_FLAGS} ${METIS_INCLUDE} ${AMD_INCLUDE} ${TACS_INCLUDE}

# By default, use the optimized flags
TACS_CC_FLAGS = ${TACS_OPT_CC_FLAGS}

# Set the linking flags to use
TACS_EXTERN_LIBS = ${AMD_LIBS} ${METIS_LIB} ${LAPACK_LIBS}
TACS_LD_FLAGS = ${EXTRA_LD_FLAGS} ${TACS_LD_CMD} ${TACS_EXTERN_LIBS}

# This is the one rule that is used to compile all the
# source code in TACS
%.o: %.cpp
    ${CXX} ${TACS_CC_FLAGS} -c $< -o $*.o
    @echo
    @echo "        --- Compiled $*.cpp successfully ---"
    @echo

【问题讨论】:

  • 您的描述中缺少一个文件:TACS_common.mk 未显示,它包含在您的Makefile 中。请将其添加到问题中,否则将很难(因为Makefile 非常复杂)为您提供有关如何解决它的提示。
  • @LuisColorado 感谢您的评论,我已添加文件。
  • 错误 target pattern contains no '%' 几乎可以肯定是使用驱动器号的问题,如下所述。因为它们,规则被解释为静态模式规则,而静态模式规则需要% 模式匹配字符。但是,该错误位于第 26 行的 src/Makefile 中,因此您必须查看那里以了解问题路径名来自何处的详细信息。
  • @MadScientist 你是对的,使用适当的语法更正路径,错误消失了。我接下来要做的是通过 Ubuntu for Windows 10(这确实是一个 WSL)安装所有先决条件,然后再次尝试使用 make 进行编译。现在我收到了类似于/usr/bin/ld: src/TACSBuckling.o:TACSBuckling.c:(.text+0x344): undefined reference to `__getreent'/usr/bin/ld: src/TACSAuxElements.o:TACSAuxElements.cpp:(.xdata+0x10): undefined reference to `__gxx_personality_seh0' 等的错误。但这看起来有点超出我原来问题的范围,不是吗?

标签: c++ linux windows makefile compilation


【解决方案1】:

您需要一个真正的答案:您无法使用 Windows 命令提示符进行编译。

获取自己的 MSYS2——它还将安装 MinGW-w64——并按照设置说明进行操作。然后启动 MSYS shell 以获取 unix-y 终端提示符(zsh、IIRC),并将目录更改为项目文件夹的头部。

要访问 Windows 文件系统,根目录将是 /c/mnt/c(抱歉,在我的移动 ATM 上,我可以在一两天内改进它)。例如,

C:\Users\qa21944\git\tacs

变成

/c/Users/qa21944/git/tacs

从那里 GNU/Windows make 命令应该可以工作了:

mingw32-make

还有这篇文章在 Windows 下使用更现代的 *nix 环境: How to install and use "make" in Windows? 不过,对于您需要的东西来说,谢谢可能有点过头了。

当我完成旅行并可以坐下来好好看看这个时,我可以改进这个答案的细节,但是你需要一个 Linux shell 终端。

【讨论】:

  • 感谢您的回答,我刚刚尝试使用 MSYS2 MinGW 64 位 shell 并按照您的指示进行操作,但不幸的是我收到以下错误:make[1]: mpicxx: No such file or directory make[1]: *** [../TACS_Common.mk:28: C:/Users/qa21944/git/tacs/src/TACSAssembler.o] Error 127 make[1]: Leaving directory '/c/Users/qa21944/git/tacs/src' mingw32-make: *** [Makefile:23: default] Error 1 这是为什么?我的PATH 环境变量中有C:\cygwin64\binC:\Program Files (x86)\Intel\oneAPI\mpi\latest\bin`,并且都包含文件mpicxx
  • 它看起来像一个错字:mpi.cxx?这是 makefile 本身的构建问题。唉,我还需要一两天才能正确看待它。你问过 TACS 的人吗?
  • 不,这不是错字,它是支持 MPI 的 C++ 编译器的名称。无论如何,感谢您的可用性,但使用 Ubuntu for Windows 被证明在一定程度上是有效的(请参阅问题的 cmets),因此 MSYS2 解决方案可能不再值得研究。
  • 好吧,够公平的。
【解决方案2】:

我无法回答,但也许我可以为你定位。

第一个nmake 不是make。它不适用于任何未专门编写为 nmake makefile 的 makefile。它仅在 Windows 上可用。所以,最好忘记它的存在。

其次,了解 make 的工作原理很重要:makefile 中的规则是目标/先决条件和配方的组合。配方不是“makefile”语法,它是一个 shell 脚本(批处理文件)。所以 make 与 shell 协同工作,运行命令。哪个壳?在 GNU/Linux 和 MacOS 等 POSIX 系统上,它非常简单:一个 POSIX shell;默认/bin/sh

在 Windows 系统上,这要简单得多:有很多选择。可能是cmd.exe。它可能是 PowerShell。它可能是用户安装的 POSIX shell。默认选择哪一个,取决于您的make 版本是如何编译的。这就是为什么您会看到 make 到 Windows 的不同“端口”的不同行为。

因此,如果您查看您尝试使用的 makefile,您会发现它们无疑是专门为 POSIX 系统编写的,并且需要 POSIX shell 和 POSIX 环境。任何尝试使用调用cmd.exe 作为其默认shell 的make 版本的尝试都会立即失败并出现语法错误("" 此时出乎意料。)。

好的,因此您找到了调用 POSIX shell 的 make 版本,并且您不再收到该错误。

但是您必须应对另一个区别:目录分隔符。在 Windows 中,他们使用反斜杠。在 POSIX 系统中,它们使用正斜杠,而反斜杠是转义字符(因此它不只是通过外壳原封不动地传递)。如果要在 POSIX shell 中使用路径,则需要确保路径使用正斜杠,否则 shell 会将它们作为转义字符删除。幸运的是,大多数 Windows 程序都接受正斜杠和反斜杠作为目录分隔符(但不是全部:例如 cmd.exe 内置工具不接受)。

那么您必须与被称为驱动器号的 Windows 可憎之物抗衡。这对于make 来说是一个很大的问题,因为对于make: 字符在各个地方都很特殊。因此,当 make 看到像 C:/foo:C:/bar 这样的行时,它的解析器会感到困惑,并且会出错。为 Windows 编译的某些版本的 make 启用启发式方法,尝试查看路径是否看起来像驱动器号。有些只是假设 POSIX 样式的路径。它们也可能是 POSIX shell 的问题:Windows 上的许多 POSIX 环境将驱动器号映射到标准 POSIX 路径,因此 C:\foo 写为 /c/foo/mnt/c/foo 或其他名称。如果要向 makefile 添加路径,则需要找出正确的映射(如果有)并使用它。

这甚至还没有开始讨论 POSIX 和 Windows 之间的其他差异......有很多。

从您上面显示的内容来看,这个项目在编写时并没有考虑到任何形式的 Windows 可移植性。考虑到它的复杂性,这并不奇怪:它需要大量的工作。所以我可以看到这些选项:

  1. 自行移植,使其与 Windows 兼容
  2. 尝试让它在 cygwin 中运行(cygwin 旨在成为在 Windows 上运行的 POSIX 风格的环境)
  3. 尝试让它在 WSL 中运行
  4. 使用运行 Linux 发行版的 VMWare、VirtualBox 等安装虚拟机并在其中构建和运行

很遗憾,我对这些方法的优缺点了解不多,因此无法就最佳课程向您提供建议。

很久以前,我选择的路线是完全摆脱 Windows,只使用 GNU/Linux。但当然,这对每个人来说都是不可能的:)。

【讨论】:

  • 嗯,首先感谢您的详细解释,现在我对我正在尝试做的事情有了更多的了解!关于您建议的选项: 1. 即使学习如何将这样的项目移植到 Windows 会很有趣(我目前没有任何能力),但我担心这对于我的最终范围来说太耗时了,即使用有限元代码2。我尝试使用cygwin,请看看我的尝试。考虑到您的讨论,我应该使用不同的 shell 而不是 cmd.exe?如果有,是哪一个?
  • 3.适用于 Windows 10 的 Ubuntu Bash 是否归类为 WSL?如果是这样(根据我的理解,如果我错了,请纠正我),你能看看我的最后一次尝试,我在哪里显示我试图用 Ubuntu Bash make 命令编译的错误? 4. 我想如果没有其他方法来编译代码,这将是一个选择。关于您选择的路线,尽管很吸引人,但不幸的是我无法做到,因为在我的大学中,我们使用了许多来自 Microsoft 套件的工具。在您看来,同时使用 Windows 和 GNU/Linux 的最佳选择是什么?
  • 更新:我尝试将 cygwin 与 Cygwin64 终端一起使用,但在从 cmd.exe 运行时遇到了同样的错误(请参阅我的问题中的相关尝试)。
  • 我不知道你的问题的答案。正如我所说,我对利弊了解不多。我不使用 Windows,也不能就在 Windows 上构建 POSIX 软件的最佳方法的详细信息向您提供建议。我不知道 Bash for Windows 是否与 WSL 相同:我从未使用过任何一种。您可以通过 Google 查找 WSL,看看它的安装是否与 Bash for Windows 不同。
  • 我接受这个答案是因为让它在 WSL 中工作是按照此脚本中指示的步骤为我工作的解决方案:github.com/smdogroup/tacs/blob/master/.github/workflows/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-09
  • 2011-07-30
  • 1970-01-01
  • 2019-07-11
  • 1970-01-01
相关资源
最近更新 更多