Skip to content
Advertisement

Calling pipenv in CMake command ModuleNotFoundError

I am trying to generate C/C++ source files via a Python script using CMake, but am running into an issue where it appears that pipenv is not working as expected.

I’ve attempted to create a simplified version of my real world example on my Github.

cmake_minimum_required(VERSION 2.8.5)
project(example)

include_directories(${PROJECT_SOURCE_DIR}/src)

find_package(Python3 COMPONENTS Interpreter REQUIRED)
find_program(PipEnv pipenv REQUIRED)

# Create command to compile the generate command
add_custom_command(
    OUTPUT
        ${CMAKE_SOURCE_DIR}/generate.py
    COMMAND ${PipEnv} install
    COMMENT "Installing pipenv dependencies [${PipEnv} install]"
    DEPENDS
        ${CMAKE_SOURCE_DIR}/generate.py
        ${CMAKE_SOURCE_DIR}/Pipfile
)

add_custom_target(
    generate_version
    COMMAND ${PipEnv} run ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/generate.py -o src/version.h config.json
    COMMENT "Generating version header [${PipEnv} run ${CMAKE_SOURCE_DIR}/generate.py -o src/version.h config.json]"
    DEPENDS
        ${CMAKE_SOURCE_DIR}/generate.py
        ${CMAKE_SOURCE_DIR}/config.json
)

add_subdirectory(src)

The error I am receiving is:

[main] Building folder: Python_example 
[build] Starting build
[proc] Executing command: "C:Program FilesCMakebincmake.EXE" --build c:/src/cmake-auto-increment-build-number/Python_example/build --config Debug --target ALL_BUILD -- /maxcpucount:10
[build] CMake is re-running because C:/src/cmake-auto-increment-build-number/Python_example/build/CMakeFiles/generate.stamp is out-of-date.
[build]   the file 'C:/src/cmake-auto-increment-build-number/Python_example/CMakeLists.txt'
[build]   is newer than 'C:/src/cmake-auto-increment-build-number/Python_example/build/CMakeFiles/generate.stamp.depend'
[build]   result='-1'
[build] -- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.18363.
[build] -- Configuring done
[build] -- Generating done
[build] -- Build files have been written to: C:/src/cmake-auto-increment-build-number/Python_example/build
[build] Microsoft (R) Build Engine version 16.3.2+e481bbf88 for .NET Framework
[build] Copyright (C) Microsoft Corporation. All rights reserved.
[build] 
[build]   Checking Build System
[build]   Generating version header [C:/Program Files/Python38/Scripts/pipenv.exe run C:/src/cmake-auto-increment-build-number/Python_example/generate.py -o src/version.h config.json]
[build]   Traceback (most recent call last):
[build]     File "C:/src/cmake-auto-increment-build-number/Python_example/generate.py", line 14, in <module>
[build]       from docopt import docopt
[build]   ModuleNotFoundError: No module named 'docopt'
[build] C:Program Files (x86)Microsoft Visual Studio2019CommunityMSBuildMicrosoftVCv160Microsoft.CppCommon.targets(230,5): error MSB6006: "cmd.exe" exited with code 1. [C:srccmake-auto-increment-build-numberPython_examplebuildgenerate_version.vcxproj]
[build] Build finished with exit code 1

I’ve tried changing the COMMAND arg for add_custom_target() to ${PipEnv} install, but that had no effect. Is there something else I need to be passing to pipenv or the CMake command to get this working?

Advertisement

Answer

Couple of errors here…

  1. Your custom command output and depends of the same file, generate.py
    note: you can see a make error in the trace

  2. By default add_custom_command will the current source dir as working directy while custom target is run in the current build dir.
    i.e. both are running in different directory -> two different pipenv used…

  3. You muse use pipenv run python instead of pipenv run ${Python3_EXECUTABLE}

  4. here my Dockerfile to run some tests

# Create a virtual environment with all tools installed
# ref: https://hub.docker.com/_/ubuntu
FROM ubuntu:rolling AS base
LABEL maintainer="mizux.dev@gmail.com"
# Install system build dependencies
ENV PATH=/usr/local/bin:$PATH
RUN apt-get update -qq 
&& apt-get install -yq git wget build-essential 
&& apt-get clean 
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install CMake 3.18.1
RUN wget "https://cmake.org/files/v3.18/cmake-3.18.1-Linux-x86_64.sh" 
&& chmod a+x cmake-3.18.1-Linux-x86_64.sh 
&& ./cmake-3.18.1-Linux-x86_64.sh --prefix=/usr/local/ --skip-license 
&& rm cmake-3.18.1-Linux-x86_64.sh
CMD [ "/usr/bin/bash" ]

# Install Python 3.8
RUN apt-get update -qq 
&& apt-get install -yq python3-dev python3-pip 
&& apt-get clean 
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Install pipenv
RUN python3 -m pip install pipenv

FROM base AS devel
WORKDIR /home/sample
COPY . .

FROM devel AS build
RUN cmake -S. -Bbuild
RUN cmake --build build --target all -v

To Build:

docker build --target=build --tag so .

To Play (i.e. stop a devel stage then spawn a container to play):

docker build --target=devel --tag so .
docker run --rm -it so

So you modified CMakeLists.txt

cmake_minimum_required(VERSION 2.8.5)
project(example)

include_directories(${PROJECT_SOURCE_DIR}/src)

find_package(Python3 COMPONENTS Interpreter REQUIRED)
find_program(PipEnv pipenv REQUIRED)

# Create command to compile the generate command
add_custom_command(
    OUTPUT Pipfile.lock
    COMMAND pwd
    COMMAND ${PipEnv} install
    COMMENT "Installing pipenv dependencies [${PipEnv} install]"
    DEPENDS
        Pipfile
    WORKING_DIRECTORY
        ${CMAKE_CURRENT_SOURCE_DIR}
)

add_custom_target(
    generate_version
    COMMAND pwd
    COMMAND ${PipEnv} run python generate.py -o src/version.h config.json
    COMMENT "Generating version header [${PipEnv} run ${CMAKE_SOURCE_DIR}/generate.py -o src/version.h config.json]"
    DEPENDS
        Pipfile.lock
        generate.py
        config.json
    WORKING_DIRECTORY
        ${CMAKE_CURRENT_SOURCE_DIR}
)

add_subdirectory(src)
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement