问题描述
我试图用 Cython 编译一个简单的例子并得到这个链接器错误(macOS,Xcode 10):
gcc -fno-strict-aliasing -I/anaconda2/envs/python2.7-base/include -arch x86_64 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/anaconda2/envs/python2.7-base/include/python2.7 -c noway.cpp -o build/temp.macosx-10.6-x86_64-2.7/noway.o -std=c++11 -Os -stdlib=libc++ -mmacosx-version-min=10.7
g++ -bundle -undefined dynamic_lookup -L/anaconda2/envs/python2.7-base/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.6-x86_64-2.7/one.o build/temp.macosx-10.6-x86_64-2.7/noway.o -L/anaconda2/envs/python2.7-base/lib -o /Users/dkotsur/Projects/InCeM/IF-MedialAxis/test/noway.so
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of OS X 10.9 [-Wdeprecated]
ld: library not found for -lstdc++
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'g++' failed with exit status 1
我的anaconda环境是这样的:
Python 2.7.15 |Anaconda custom (64-bit)| (default, May 1 2018, 18:37:05)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
对于 Mac,anaconda 似乎使用 libstdc++ 而不是 libc++。 但我不知道如何解决它。
有没有人有类似的东西? 有关如何处理的任何线索?
这是我的代码 setup.py
if platform.system() == "Windows":
extra_args = ["/std:c++latest", "/EHsc"]
elif platform.system() == "Darwin":
extra_args = ['-std=c++11', "-Os", "-stdlib=libc++", "-mmacosx-version-min=10.7"]
else:
extra_args = []
compile_files = [
"one.pyx",
"noway.cpp",
]
include_paths = [
]
ext_modules = [Extension("noway", compile_files,
language='c++',
include_dirs=include_paths,
extra_compile_args=extra_args)]
setup(cmdclass={'build_ext': build_ext}, ext_modules=cythonize(ext_modules))
一个.pyx:
import cython
cdef extern from "noway.hpp":
cdef void noway();
def nway():
noway()
noway.hpp
#ifndef noway_h
#define noway_h
void noway();
#endif
noway.cpp
#include "noway.hpp"
#include <iostream>
void noway() {
std::cout << "No way!!!" << std::endl;
}
1楼
谢谢,@ead 发表评论。 你帮了很多忙。
我通过将-stdlib=stdc++
添加到额外的链接参数而不是编译参数来修复 setup.py。
我还必须将-mmacosx-version-min=10.9
到额外的链接参数中。
所以, setup.py
现在看起来像这样:
import platform
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
compile_extra_args = []
link_extra_args = []
if platform.system() == "Windows":
compile_extra_args = ["/std:c++latest", "/EHsc"]
elif platform.system() == "Darwin":
compile_extra_args = ['-std=c++11', "-mmacosx-version-min=10.9"]
link_extra_args = ["-stdlib=libc++", "-mmacosx-version-min=10.9"]
compile_files = [
"one.pyx",
"noway.cpp",
]
ext_modules = [Extension("noway", compile_files,
language='c++',
extra_compile_args=compile_extra_args,
extra_link_args=link_extra_args)]
setup(cmdclass={'build_ext': build_ext}, ext_modules=cythonize(ext_modules))
2楼
我遇到了一个相关的程序,试图更新一个旧的 ionics-2 程序,该程序使用带有大量 python 脚本的各种节点模块。 我最终编写了一个程序,该程序允许我使用 3rd 方节点而无需修补它们来解决此问题。 我在提出解决方案时遇到了这篇文章。
该程序基本上即时修补了 clang++ 参数以替换 -mmacosx-version-min=xxx 参数并将环境日志和参数写入 /tmp/vardump.txt
要使用它,只需使用以下内容构建它:
gcc clang_force.c -o clang_force
然后将其复制到 /usr/local/bin cp clang_force /usr/local/bin 然后更改 CXX 环境变量以使用它。 export CXX=/usr/local/bin/force_clang
就是这样。 然后再次执行'npm install'或你的python脚本,一切都很好。 希望有人觉得它有用。
在此站点上获取代码修复: :
/**************************************************************************
Force clang to use version 10.9 or greater to allow building legacy code
(overrides any -mmacosx-version-min params passed in)
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define WAIT_FOR_COMPLETION
static int exec_prog(char **argv);
int main(int argc, char **argv, char **envp)
{
FILE *fp;
int rc = 0;
fp = fopen("/tmp/vardump.txt","a+");
if (fp!=NULL) {
for (char **env = envp; *env != 0; env++)
{
char *thisEnv = *env;
fprintf(fp,"%s\n", thisEnv);
}
int counter;
fprintf(fp,"Program Name Is: %s",argv[0]);
if(argc==1)
fprintf(fp,"\nNo Extra Command Line Argument Passed Other Than Program Name");
if(argc>=2)
{
fprintf(fp,"\nNumber Of Arguments Passed: %d",argc);
fprintf(fp,"\n----Following Are The Command Line Arguments Passed----");
for(counter=0;counter<argc;counter++) {
fprintf(fp,"\nargv[%d]: %s",counter,argv[counter]);
if (strncmp(argv[counter],"-mmacosx-version-min",20)==0) {
argv[counter] = "-mmacosx-version-min=10.9";
fprintf(fp,"\nForcing argument to %s",argv[counter]);
}
}
}
fclose(fp);
argv[0] = "/usr/bin/clang++";
rc = exec_prog(argv);
}
return rc;
}
static int exec_prog(char **argv)
{
FILE *fp;
fp = fopen("/tmp/vardump.txt","a+");
if (fp!=NULL) {
fprintf(fp,"\nExecuting %s\n",argv[0]);
fclose(fp);
}
pid_t my_pid;
int status, timeout /* unused ifdef WAIT_FOR_COMPLETION */;
if (0 == (my_pid = fork())) {
if (-1 == execve(argv[0], (char **)argv , NULL)) {
perror("child process execve failed [%m]");
return -1;
}
}
#ifdef WAIT_FOR_COMPLETION
timeout = 1000;
while (0 == waitpid(my_pid , &status , WNOHANG)) {
if ( --timeout < 0 ) {
perror("timeout");
return -1;
}
sleep(1);
}
fp = fopen("/tmp/vardump.txt","a+");
if (fp!=NULL) {
fprintf(fp,"\n %s WEXITSTATUS %d WIFEXITED %d [status %d]\n",
argv[0], WEXITSTATUS(status), WIFEXITED(status), status);
if (1 != WIFEXITED(status) || 0 != WEXITSTATUS(status)) {
perror("failed, halt system");
return -1;
}
fclose(fp);
}
#endif
return 0;
}