Python distutils по-разному строит расширения на разных машинах - PullRequest
1 голос
/ 30 июня 2010

Я работал над модулем расширения Python с большим количеством файлов. При сборке на одной машине python setup.py build с радостью обнаружит измененные файлы, создаст только эти файлы и объединит все вместе, как make. Однако на другом компьютере одно изменение любого файла вызывает перекомпиляцию всех источников.

Просто чтобы было ясно. Обе машины определяют, когда пакет обновлен, и ничего не будут делать. Только когда один файл изменяется, его поведение расходится.

Почему вторая машина делает это?

Машина 1 (выполняет проверку и сборку зависимостей для каждого файла.)

Python 2.6.4 (r264:75706, Feb 15 2010, 17:06:03) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

setuptools-0.6c11-py2.6

LSB Version: :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch
Distributor ID: CentOS
Description: CentOS release 5.4 (Final)
Release: 5.4
Codename: Final

Машина 2 (восстанавливает все, когда изменяется один исходный файл.)

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

setuptools-0.6c11-py2.6

No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 10.04 LTS
Release: 10.04
Codename: lucid

Ответы [ 2 ]

2 голосов
/ 10 октября 2011

Я заглянул в репозиторий Mercurial и обнаружил это изменение:

Проблема # 5372 : Прекратить повторное использование файлов .o в компиляторе Distutils (поскольку дополнительные параметры расширения могут изменить выводбез изменения файла .c).

IOW, это была упрощенная оптимизация, которая была удалена.

1 голос
/ 30 июня 2010

Я проследил это до изменения в distutils между Python 2.6.4 и Python 2.6.5. Два метода в distutils.ccompiler.CCompiler, а именно _setup_compile и _prep_compile, удалили один и тот же кусок кода:

if self.force:
    skip_source = {}            # rebuild everything
    for source in sources:
        skip_source[source] = 0
elif depends is None:
    # If depends is None, figure out which source files we
    # have to recompile according to a simplistic check. We
    # just compare the source and object file, no deep
    # dependency checking involving header files.
    skip_source = {}            # rebuild everything
    for source in sources:      # no wait, rebuild nothing
        skip_source[source] = 1

    n_sources, n_objects = newer_pairwise(sources, objects)
    for source in n_sources:    # no really, only rebuild what's
        skip_source[source] = 0 # out-of-date
else:
    # If depends is a list of files, then do a different
    # simplistic check.  Assume that each object depends on
    # its source and all files in the depends list.
    skip_source = {}
    # L contains all the depends plus a spot at the end for a
    # particular source file
    L = depends[:] + [None]
    for i in range(len(objects)):
        source = sources[i]
        L[-1] = source
        if newer_group(L, objects[i]):
            skip_source[source] = 0
        else:
            skip_source[source] = 1

Этот код проверяет каждый исходный файл на соответствие его целевому объекту и отмечает, что он пропускается, если он старше целевого. Я не знаю, почему это было удалено, но это объясняет несоответствие. Когда я возвращаю его обратно в качестве теста, компилятор возвращается к анализу зависимостей для каждого источника.

...