premake5實例教程

premakeExample

1 簡介

本文講解如何基於premake5創建一個典型的C++解決方案,該解決方案包含三個項目:

  • 一個依賴GLFW動態庫的動態庫項目ExampleDll
  • 一個依賴ExampleDll動態庫的窗口程序APP
  • 一個基於Catch的單元測試程序UnitTest

所有代碼已上傳Github,鏈接

2 你需要準備

  • premake5.exe程序
  • 一個文本編輯器
  • 一個支持C++11的編譯器,因爲源代碼使用了C++11特性
  • 一個支持OpenGL 1.1的顯卡

3 文件的組織結構

首先需要確定整個解決方案中源代碼、三方庫、二進制等文件的組織結構,本文創建的文件結構如下:

premakeExample/
 |–premake5.lua (premake腳本文件)
 |–prj/ (生成的解決方案與各項目配置文件路徑)
 |–build/
 | |–target/ (目標生成路徑)
 | |–obj/ (中間文件生成路徑)
 |–bin/ (最終發佈的二進制文件路徑)
 |–3rd/ (第三方庫文件路徑)
 | |–Catch (Catch單元測試框架頭文件路徑)
 | |–glfw (glfw三方庫相關文件路徑)

4 下載所需文件

本文以64位系統爲例,需下載64位二進制庫,也可以下載32位,但要記得在後面lua腳本中改變architecture配置。

將下載解壓後的include和lib-vc*文件夾放在premakeExample/3rd/glfw文件夾下,*指代不同的vs版本,需與後續生成配置文件的vs版本一致。

將lib-vc*路徑下的glfw3.dll拷貝紙premakeExample/bin路徑下

  • catch是一個只有頭文件的依賴庫,將Catch.hpp(下載)放在premakeExample/3rd/Catch/include路徑下即可。

5 添加代碼

5.1 ExampleDll

ExampleDll庫只是對glfw中的GLFWwindow進行了簡單封裝,隱藏了window的內部實現細節。Window類通過_declspec(dllexport)導出。

  • ExampleDll.hpp代碼如下:
#ifndef EXAMPLE_DLL_HPP
#define EXAMPLE_DLL_HPP 1
#include <string>
#include <memory>
struct GLFWwindow;
namespace ExDLL
{	
	class _declspec(dllexport) Window
	{
	public:
		Window(int width, int  height, const std::string& title);
		~Window();
		bool shouldClose() const noexcept;
		void pollEvents() const noexcept;
		void swapBuffers() const noexcept;
		std::pair<int, int> getWindowSize() const noexcept;	
	private:
		GLFWwindow* wnd;
	};
}
#endif
  • ExampleDll.cpp代碼如下
#include "ExampleDll.hpp"
#include <GLFW/glfw3.h>
	
namespace ExDLL
{
	Window::Window(int width, int height, const std::string& title)
	{
		glfwInit();
		wnd = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
		glfwMakeContextCurrent(wnd);
	}
	
	Window::~Window()
	{
		glfwDestroyWindow(wnd);
		glfwTerminate();
	}

	bool Window::shouldClose() const noexcept
	{
		return glfwWindowShouldClose(wnd) != 0;
	}

	void Window::pollEvents() const noexcept
	{
		glfwPollEvents();
	}

	void Window::swapBuffers() const noexcept
	{
		glfwSwapBuffers(wnd);
	}

	std::pair<int, int> Window::getWindowSize() const noexcept
	{
		std::pair<int, int> sz{};
		glfwGetWindowSize(wnd, &sz.first, &sz.second);
		return sz;
	}
}

5.2 App

應用程序依賴Exampledll,創建一個窗口應用程序,並運用固定管線繪製一個紅色的三角形。當然本教程不講解OpenGL,如果想要學習OpenGL的使用,應該學習更先進的可編程管線。

  • main.cpp代碼如下:
#include <ExampleDll.hpp>

#if defined _WIN32
    //Windows平臺使用OpenGL需要包含Windows.h
	#include <Windows.h>
	//消除窗口程序的控制檯界面
	#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#endif
#include <gl/GL.h>

//導入ExampleDll中的Window類
class _declspec(dllimport) ExDLL::Window;

int main()
{
	ExDLL::Window window{ 800, 600, "Hello World!" };
	while (!window.shouldClose())
	{
		window.pollEvents();
		//爲簡單起見,使用了古老的固定管線
		glColor3f(1.0, 0.0, 0.0);
		glBegin(GL_TRIANGLES);
			glVertex2f(-0.5f, -0.5f);
			glVertex2f(0.5f, -0.5f);
			glVertex2f(0, 0.5f);
		glEnd();
		window.swapBuffers();
	}
	return 0;
}

5.3 UnitTest

單元測試程序檢查創建的窗口大小是否與參數要求的大小一致。

  • Test.cpp代碼如下:
#define CATCH_CONFIG_MAIN
#include <Catch.hpp>

#include <ExampleDll.hpp>

TEST_CASE("Window tests", "[ExampleDll]")
{
	using namespace ExDLL;
	Window w{ 600, 400, "Test Window" };

	auto size = w.getWindowSize();

	REQUIRE(size.first == 600);
	REQUIRE(size.second == 400);
}

6 編寫premake5.lua腳本文件

premake5.lua是生成工程配置文件的核心。

  • premake5.lua代碼如下:
-- 最終解決方案的名稱
workspace "premakeExample"
	-- 解決方案與各項目配置文件生成路徑
	location "prj"
	-- 指定語言
	language "C++"
	-- 指定架構 x64 或 x86 或  x86_64
	architecture "x64"
	-- 配置類型
	configurations {"Debug","Release"}
	-- 針對Debug配置類型的參數設置
	filter {"configurations:Debug"}
		symbols "On"
	-- 針對Release配置類型的參數設置
	filter {"configurations:Release"}
		optimize "On"
	-- 重置過濾器的其他設定
	filter {}
	-- 目標文件生成路徑 如%{prj.name}爲內置的宏,指項目的名稱,如後面的ExampleDll,App等
	targetdir ("build/target/%{prj.name}/%{cfg.longname}")
	-- 中間文件生成路徑
	objdir ("build/obj/%{prj.name}/%{cfg.longname}")
	-- 編譯後命令行,將目標文件拷貝至bin文件夾,注意../bin/是prj文件夾的相對路徑
	postbuildcommands{
		("{COPY} %{cfg.buildtarget.relpath} \"../bin/\"")
	}
	
-- 定義函數,包含glfw三方庫頭文件,可被其他工程調用
function includeGLFW()
	includedirs "3rd/glfw/include"
end
-- 定義函數,鏈接glfw三方庫
function linkGLFW()
	-- 指定lib的文件路徑
	libdirs "3rd/glfw/lib-vc2019"
	-- 指定lib文件名,即glfw3dll.lib,此處使用的是動態庫
	links "glfw3dll"
end

-- ExampleDll項目
project "ExampleDll"
	-- 類型爲動態庫項目
	kind "SharedLib"
	-- 代碼文件,即ExampleDll文件夾下的所有文件
	files "src/ExampleDll/**"
	-- 包含glfw頭文件
	includeGLFW()
	-- 鏈接glfw三方庫
	linkGLFW()

-- 定義函數,鏈接ExampleDll動態庫
function useExampleDLL()
	includedirs "src/ExampleDll"
	links "ExampleDll"
end

-- App應用程序
project "App"
	-- 類型爲控制檯程序
	kind "ConsoleApp"
	-- 代碼文件
	files "src/App/**"
	-- 鏈接ExampleDll動態庫
	useExampleDLL()
	-- windows平臺使用OpenGL需鏈接OpenGL32
	filter "system:windows"
		links {"OpenGL32"}

-- 定義函數,包含Catch
function includeCatch()
	includedirs "3rd/Catch/Include"
	-- 預定義宏,C++版本爲C++11及以上
	defines "CATCH_CPP11_OR_GREATER"
end

-- UnitTests單元測試項目
project "UnitTests"
	-- 類型爲控制檯程序
	kind "ConsoleApp"
	-- 代碼文件
	files "src/UnitTests/**"
	-- 包含Catch
	includeCatch()
	-- 鏈接ExamleDll
	useExampleDLL()

7 生成工程文件並編譯

premake5.exe運行時時會尋找調用命令路徑下的premake5.lua文件,如果想生成工程配置文件,需在premakeExample路徑下調用premake5.exe <action>,其中action可指定爲vs2019gmake,本文以vs2019爲例。
在這裏插入圖片描述
執行命令後在prj文件夾下,生成的工程配置文件如下:
在這裏插入圖片描述
打開premakeExample.sln編譯解決方案,在bin路徑下運行app.exe,效果如下:
在這裏插入圖片描述
命令行打開單元測試程序UnitTests.exe,效果如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章