学习的过程中感觉jupyter用来学习十分的方便,但是学C++的时候发现在windows里面很少有jupyter编写C++,因此编写了一段代码用来学习。

该代码需要python,插件:C/C++ Extension Pack,C/C++,C/C++ Themes

这段代码的本质是在 Python Jupyter kernel 里注册一个自定义单元格命令 %%cpp,然后 Notebook 单元格里写 C++,然后由 Python 自动保存、编译、运行。

以下是实现结果

实现过程

新建一个cpp_magic.py,里面的代码如下

from IPython.core.magic import register_cell_magic
from pathlib import Path
import subprocess
import sys
import os
import time


def decode_output(data: bytes) -> str:
    for enc in ("utf-8", "gbk", "mbcs"):
        try:
            return data.decode(enc)
        except Exception:
            pass
    return data.decode("utf-8", errors="replace")


def find_vcvars64():
    candidates = [
        Path(r"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"),
        Path(r"C:\Program Files\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"),
    ]

    for p in candidates:
        if p.exists():
            return str(p)

    roots = [
        Path(r"C:\Program Files (x86)\Microsoft Visual Studio"),
        Path(r"C:\Program Files\Microsoft Visual Studio"),
    ]

    for root in roots:
        if root.exists():
            matches = list(root.glob(r"**\VC\Auxiliary\Build\vcvars64.bat"))
            if matches:
                return str(matches[0])

    return None


def get_msvc_env():
    vcvars64 = find_vcvars64()
    if not vcvars64:
        raise RuntimeError("找不到 vcvars64.bat。")

    cmd = f'cmd /s /c "call "{vcvars64}" >nul && set"'

    result = subprocess.run(
        cmd,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

    if result.returncode != 0:
        print(decode_output(result.stderr), file=sys.stderr)
        raise RuntimeError("初始化 MSVC 环境失败。")

    env = os.environ.copy()
    output = decode_output(result.stdout)

    for line in output.splitlines():
        if "=" in line:
            key, value = line.split("=", 1)
            if key:
                env[key] = value

    return env


def find_exe_in_env(exe_name, env):
    paths = env.get("PATH", "").split(os.pathsep)

    for folder in paths:
        p = Path(folder) / exe_name
        if p.exists():
            return str(p)

    return None


MSVC_ENV = get_msvc_env()
CL_EXE = find_exe_in_env("cl.exe", MSVC_ENV)

if not CL_EXE:
    raise RuntimeError("MSVC 环境已初始化,但仍然找不到 cl.exe。")


@register_cell_magic
def cpp(line, cell):
    name = line.strip() or "main"
    name = Path(name).stem

    cpp_path = Path.cwd() / f"{name}.cpp"
    exe_path = Path.cwd() / f"{name}.exe"

    cpp_path.write_text(cell, encoding="utf-8")

    compile_cmd = [
        CL_EXE,
        "/nologo",
        "/EHsc",
        "/std:c++17",
        "/utf-8",
        str(cpp_path),
        f"/Fe:{exe_path}"
    ]

    t0 = time.perf_counter()

    compile_result = subprocess.run(
        compile_cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        env=MSVC_ENV
    )

    t1 = time.perf_counter()

    compile_stdout = decode_output(compile_result.stdout)
    compile_stderr = decode_output(compile_result.stderr)

    if compile_result.returncode != 0:
        if compile_stdout:
            print(compile_stdout, end="")
        if compile_stderr:
            print(compile_stderr, end="", file=sys.stderr)
        print(f"\n编译失败。编译耗时:{t1 - t0:.3f}s")
        return

    run_result = subprocess.run(
        [str(exe_path)],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

    t2 = time.perf_counter()

    run_stdout = decode_output(run_result.stdout)
    run_stderr = decode_output(run_result.stderr)

    if run_stdout:
        print(run_stdout, end="")
    if run_stderr:
        print(run_stderr, end="", file=sys.stderr)

    print(f"\n编译耗时:{t1 - t0:.3f}s")
    print(f"运行耗时:{t2 - t1:.3f}s")
    print(f"总耗时:{t2 - t0:.3f}s")

在jupyter notebook第一个单元格中

%run cpp_magic.py

在每个单元格中首行必写

%%cpp tt

tt是随便写的,因为本质是先生成一个c++文件此处会生成一个tt.cpp文件

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐