Windows下OpenGL完全独立内联环境配置(Mingw/Cmake/Ninja)

Wednesday, May 8, 2024
本文共1442字
3分钟阅读时长

⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/posts/windows%E4%B8%8Bopengl%E5%AE%8C%E5%85%A8%E7%8B%AC%E7%AB%8B%E5%86%85%E8%81%94%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/。商业转载请联系作者获得授权,非商业转载请注明出处!

There is no fear for one whose mind is not filled with desires. — The Buddha

引言

因为实在是受不了电脑上乌烟瘴气的C++环境,并且C盘几乎快被我塞满了,于是一气之下删掉了VS(并且一点也不想再下回来)

最近突然想学一下OpenGL,于是准备配置OpenGL的环境

但是我的电脑上已经没有编译器了,我又不想用MSVC,也不想开虚拟机,于是我选择了Mingw。但是我不想为了Mingw安装一堆其他的环境(Cygwin等),所以我选择了Mingw-builds:

文内图片

因为强迫症,所以我不想让这个Mingw变成我电脑的全局配置。又因为既然这么做了,就想构建一个完全独立、几乎不依赖于外界(当然还是要依赖操作系统的底层调用的)的内联环境。因此我一不做二不休干脆把cmake和ninja也下在项目目录内,并让整个项目依赖于项目内独立的Mingw/cmake/ninja

想象一下,当你在GitHub看到一个很好玩的项目,但是下载下来因为这样那样的依赖不满足而无法构建,于是又要不停地搜索如何下载这些依赖项……

所以现在问题变成了如何使用独立的Mingw/cmake/ninja构建项目了

一些需要用到的宏

cmake中配置项目可以使用宏:

  • CMAKE_C_COMPILER:C语言编译器
  • CMAKE_CXX_COMPILER:C++编译器
  • CMAKE_MAKE_PROGRAM:构建工具(Ninja、make那些)
  • CMAKE_BUILD_TYPE:构建类型(Release、DeBug那些)

通过设置这些宏,并显示地使用路径指向项目内的cmake,我们就可以做到独立干净地编译

编译OpenGL

我们可以通过cmake的--install-prefix选项来设置安装的路径,并在构建命令中加上--target install来执行安装任务。这个安装的路径一定要设置好,放在项目内,不然的话就会变成全局安装。

因此,简单来说,构建命令基本上是:

cmake -S <源代码路径> -B <生成配置路径> -S <构建工具类型> --install-prefix <安装路径> -D<各种宏>
cmake --build <构建路径> --target install --parallel <线程数>

这样我们就编译安装好了GLFW,至于GLAD,实际上GLFW内是有一个GLAD的,并且经过我的测试这个GLAD是可以用的,路径在<GLFW路径>/deps/glad,这里我们可以把整个deps都复制到我们整个项目的include文件夹内,反正这只是一个小项目的环境,怎么折腾污染都不会蔓延(只要遵循一定的规则)。

自动化脚本

因为这个步骤非常的繁琐,而且各个操作系统的脚本风格都各不相同,所以我选择了跨平台的Python脚本

准备环境脚本:

import os
import shutil
import sys
import subprocess
import zipfile
import requests

import requests
from tqdm import tqdm
import py7zr

proxies = {
    "http": "http://127.0.0.1:7897",
    "https": "http://127.0.0.1:7897",
}

def download_file(url, filename):
    global proxies
    # 发送 GET 请求
    response = requests.get(url, proxies=proxies, stream=True)  # 添加stream=True以启用流下载
    # 确保请求成功
    response.raise_for_status()

    # 获取文件总大小
    total_size = int(response.headers.get('content-length', 0))

    # 打开一个文件并写入内容
    with open(filename, 'wb') as f, tqdm(
        desc=filename,
        total=total_size,
        unit='B',
        unit_scale=True,
        unit_divisor=1024,
    ) as bar:
        for data in response.iter_content(chunk_size=1024):
            size = f.write(data)
            bar.update(size)

download_url = 'https://github.com/niXman/mingw-builds-binaries/releases/download/13.2.0-rt_v11-rev0/x86_64-13.2.0-release-win32-seh-msvcrt-rt_v11-rev0.7z'
save_path = 'mingw.7z'
download_file(download_url, save_path)
extract_to_path = '.'
shutil.rmtree("mingw64", True)
with py7zr.SevenZipFile(save_path, mode='r') as z:
    z.extractall(extract_to_path)
os.remove(save_path)

download_url = 'https://github.com/Kitware/CMake/releases/download/v3.29.3/cmake-3.29.3-windows-x86_64.zip'
save_path = 'cmake.zip'
download_file(download_url, save_path)
extract_to_path = '.'
shutil.rmtree("cmake-3.29.3", True)
with zipfile.ZipFile(save_path, 'r') as zip_ref:
    zip_ref.extractall(extract_to_path)
os.rename("cmake-3.29.3-windows-x86_64", "cmake-3.29.3")
os.remove(save_path)

download_url = 'https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip'
save_path = 'glfw-3.4.zip'
download_file(download_url, save_path)
extract_to_path = '.'
shutil.rmtree('glfw-3.4', True)
# 打开 ZIP 文件并解压全部内容
with zipfile.ZipFile(save_path, 'r') as zip_ref:
    zip_ref.extractall(extract_to_path)
os.remove(save_path)
    
download_url = "https://github.com/ninja-build/ninja/releases/download/v1.12.0/ninja-win.zip"
save_path = 'ninja-win.zip'
download_file(download_url, save_path)
extract_to_path = 'ninja'
shutil.rmtree(extract_to_path, True)
# 打开 ZIP 文件并解压全部内容
with zipfile.ZipFile(save_path, 'r') as zip_ref:
    zip_ref.extractall(extract_to_path)
os.remove(save_path)

LIB_NAME = "glfw-3.4"
BUILD_TYPE = "Release"
LIB_SOURCE = os.path.join(os.path.abspath(os.curdir), LIB_NAME)
LIB_INSTALL = os.path.join(os.path.abspath(os.curdir), "GLFW")
BUILD_DIR = os.path.join(LIB_SOURCE, "build")
shutil.rmtree(BUILD_DIR, True)
shutil.rmtree(LIB_INSTALL, True)
CMAKE_EXECUTABLE = os.path.join(os.path.abspath(os.curdir), "cmake-3.29.3", "bin", "cmake.exe")
MINGW_DIR = os.path.join(os.path.abspath(os.curdir), "mingw64", "bin")
CMAKE_C_COMPILER = os.path.join(MINGW_DIR, "gcc.exe")
CMAKE_CXX_COMPILER = os.path.join(MINGW_DIR, "g++.exe")
CMAKE_MAKE_PROGRAM = os.path.join(os.path.abspath(os.curdir), "ninja", "ninja.exe")
# CMAKE_MAKE_PROGRAM = os.path.join(MINGW_DIR, "mingw32-make.exe")

os.system(f'''set PATH=%PATH%;{MINGW_DIR} && {CMAKE_EXECUTABLE} -S {LIB_SOURCE} -G "Ninja" -B {BUILD_DIR} -DCMAKE_C_COMPILER={CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER={CMAKE_CXX_COMPILER} -DCMAKE_MAKE_PROGRAM={CMAKE_MAKE_PROGRAM} -DCMAKE_BUILD_TYPE={BUILD_TYPE} --install-prefix {LIB_INSTALL} && {CMAKE_EXECUTABLE} --build {BUILD_DIR} --target install --parallel 8
''')

shutil.copytree(os.path.join(LIB_SOURCE, "deps"), os.path.join(LIB_INSTALL, "include", "deps"))

requirements.txt:

# Python 3.8.19
py7zr~=0.21.0
Requests~=2.31.0
tqdm~=4.66.4