使用Xcode 10编译Cython

时间:2018-09-22 21:11:57

标签: python xcode cython

我试图用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))

one.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;
}

2 个答案:

答案 0 :(得分:3)

谢谢@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))

答案 1 :(得分:0)

我遇到了一个相关程序,试图更新一个旧的ionics-2程序,该程序使用带有大量python脚本的各种节点模块。我最终编写了一个程序,该程序使我可以使用第三方节点而无需修补它们来解决此问题。提出解决方案时,我碰到了这篇文章。

该程序基本上是在运行时修补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环境变​​量以使用它。 导出CXX = / usr / local / bin / force_clang

就是这样。然后只需再次执行“ npm install”或您的python脚本,一切都很好。希望有人觉得它有用。

在此站点上获取代码修复: https://github.com/nodejs/node-gyp/issues/1827

/**************************************************************************
 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;
}