Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion commandLine/src/defines.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#define OFPROJECTGENERATOR_MAJOR_VERSION "0"
#define OFPROJECTGENERATOR_MINOR_VERSION "109"
#define OFPROJECTGENERATOR_MINOR_VERSION "110"
#define OFPROJECTGENERATOR_PATCH_VERSION "0"

#define PG_VERSION (OFPROJECTGENERATOR_MAJOR_VERSION "." OFPROJECTGENERATOR_MINOR_VERSION "." OFPROJECTGENERATOR_PATCH_VERSION)
Expand Down
16 changes: 15 additions & 1 deletion commandLine/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ enum optionIndex { UNKNOWN,
CLEANNAME_DISABLE,
DEFINES,
POSTBUILD,
MSYS2ENV
MSYS2ENV,
EMSCRIPTEN_WASM
};

constexpr option::Descriptor usage[] = {
Expand Down Expand Up @@ -64,6 +65,7 @@ constexpr option::Descriptor usage[] = {
{ DEFINES, 0, "D", "defines", option::Arg::Optional, " --defines, -D \tpreprocessor defines list (such as OF_USE_ANGLE=1,MY_FLAG)" },
{ POSTBUILD, 0, "P", "postbuild", option::Arg::Optional, " --postbuild, -P \tscript to run after the project compiles (Xcode run script / VS post-build event)" },
{ MSYS2ENV, 0, "k", "msys2env", option::Arg::Optional, " --msys2env, -k \tMSYS2 environment for the msys2 / VSCode targets: ucrt64 (default) | mingw64 | clang64 | clangarm64" },
{ EMSCRIPTEN_WASM, 0, "W", "emscripten-wasm", option::Arg::Optional, " --emscripten-wasm, -W \temscripten WebAssembly: 32 (default) | 64 (wasm64, MEMORY64), written to config.make PROJECT_EMSCRIPTEN_WASM" },

{ 0, 0, 0, 0, 0, 0 }
};
Expand Down Expand Up @@ -93,6 +95,7 @@ vector<string> targets;
vector<string> frameworks;
vector<string> defines;
string postBuildScript;
string emscriptenWasm; // empty keeps the project's config.make value
string ofPathEnv;
string templateName;
string msys2Env = "ucrt64";
Expand Down Expand Up @@ -264,6 +267,7 @@ void updateProject(const fs::path & path, const string & target, bool bConsiderP
if (!bDryRun) {
auto project = getTargetProject(target);
project->setMsys2Environment(msys2Env);
project->setEmscriptenWasm(emscriptenWasm);
project->create(path, templateName);

if (bConsiderParameterAddons && bAddonsPassedIn) {
Expand Down Expand Up @@ -615,6 +619,15 @@ int main(int argc, char ** argv) {
defines = ofSplitString(options[DEFINES].arg, ",", true, true);
}

if (options[EMSCRIPTEN_WASM].count() > 0 && options[EMSCRIPTEN_WASM].arg != NULL) {
std::string bits = ofTrim(options[EMSCRIPTEN_WASM].arg);
if (bits == "32" || bits == "64") {
emscriptenWasm = bits;
} else {
ofLogWarning() << "unknown emscripten wasm " << bits << ", expected 32 or 64 - keeping the project's setting";
}
}

if (options[POSTBUILD].count() > 0 && options[POSTBUILD].arg != NULL) {
postBuildScript = ofTrim(options[POSTBUILD].arg);
}
Expand Down Expand Up @@ -759,6 +772,7 @@ int main(int argc, char ** argv) {
ofLogNotice() << "project path is: [" << projectPath << "]";
auto project = getTargetProject(t);
project->setMsys2Environment(msys2Env);
project->setEmscriptenWasm(emscriptenWasm);
project->create(projectPath, templateName);
if(bAddonsPassedIn){
for (auto & addon : addons) {
Expand Down
116 changes: 116 additions & 0 deletions commandLine/src/projects/baseProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#include "baseProject.h"
#include <regex>
#include "ofLog.h"
#include "Utils.h"
#include "ofConstants.h"
Expand All @@ -31,6 +32,7 @@ fs::path baseProject::getPlatformTemplateDir() {
|| target == "linuxarmv6l"
|| target == "linuxarmv7l"
|| target == "linuxaarch64"
|| target == "emscripten" // vscode base, emscripten template overlaid in create()
) {
folder = "vscode";
}
Expand Down Expand Up @@ -110,6 +112,36 @@ vector<baseProject::Template> baseProject::listAvailableTemplates(string target)
return templates;
}

// PROJECT_EMSCRIPTEN_WASM from config.make; the old EMSCRIPTEN_MEMORY64=1 also means 64
static std::string readEmscriptenWasm(const fs::path & configMake) {
std::string bits;
if (!fs::exists(configMake)) return bits;
for (auto & line : fileToStrings(configMake)) {
auto config = ofTrim(line);
if (config.empty() || config[0] == '#') continue;
auto eq = config.find('=');
if (eq == std::string::npos) continue;
auto var = ofTrim(config.substr(0, eq));
auto value = ofTrim(config.substr(eq + 1));
if (var == "PROJECT_EMSCRIPTEN_WASM") bits = value;
else if (var == "EMSCRIPTEN_MEMORY64" && value == "1" && bits.empty()) bits = "64";
}
return bits;
}

static const std::string OF_CMAKE_INCLUDE { "libs/openFrameworksCompiled/project/CMake/openFrameworks.cmake" };

// set(PROJECT_EMSCRIPTEN_WASM 64) written by PG into an openFrameworks CMakeLists.txt (openFrameworks#8586)
static std::string readCMakeEmscriptenWasm(const fs::path & cmakeLists) {
static const std::regex wasmSet(R"re(^\s*set\(\s*PROJECT_EMSCRIPTEN_WASM\s+(32|64)\b)re");
std::smatch m;
if (!fs::exists(cmakeLists)) return "";
for (auto & line : fileToStrings(cmakeLists)) {
if (std::regex_search(line, m, wasmSet)) return m[1];
}
return "";
}

bool baseProject::create(const fs::path & _path, string templateName){
// alert("baseProject::create " + path.string() + " : " + templateName, 35);
auto path = _path; // just because it is const
Expand Down Expand Up @@ -152,6 +184,29 @@ bool baseProject::create(const fs::path & _path, string templateName){
projectPath = normalizePath(projectPath);
ofLogNotice() << "projectPath: [" << projectPath << "]";
projectName = projectPath.filename().string();

// read before template copies can replace config.make
emscriptenWasm = emscriptenWasmOption;
if (emscriptenWasm.empty()) emscriptenWasm = readEmscriptenWasm(projectDir / "config.make");
if (emscriptenWasm.empty()) emscriptenWasm = readCMakeEmscriptenWasm(projectDir / "CMakeLists.txt");
if (!emscriptenWasm.empty()) {
ofLogNotice() << "{ \"emscriptenWasm\": \"" << emscriptenWasm << "\" }";
}
if (emscriptenWasm == "64") {
bool bHasWasm64Libs = false;
if (fs::exists(getOFRoot() / "libs")) {
for (auto & lib : fs::directory_iterator(getOFRoot() / "libs")) {
if (fs::exists(lib.path() / "lib" / "emscripten" / "WASM64")) {
bHasWasm64Libs = true;
break;
}
}
}
if (!bHasWasm64Libs) {
ofLogWarning() << "wasm64: no libs/*/lib/emscripten/WASM64 found. Run BITS=64 scripts/emscripten/download_libs.sh (replaces the installed lib/emscripten libs)";
}
}

bool bDoesSrcDirExist = false;
fs::path projectSrc { projectDir / "src" };
if (fs::exists(projectSrc) && fs::is_directory(projectSrc)) {
Expand All @@ -174,6 +229,22 @@ bool baseProject::create(const fs::path & _path, string templateName){
ofLogError() << "{ \"errorMessage\": \"" << "baseProject::create createProjectFile failed" << "\", \"status:\" \"EXIT_FAILURE\" }";
return false;
}
// cmake template (openFrameworks#8586) is a single CMakeLists.txt with no template.config; keep an existing one
if (templateName == "cmake") {
fs::path cmakeTemplate { getOFRoot() / templatesFolder / "cmake" / "CMakeLists.txt" };
if (!fs::exists(cmakeTemplate)) {
ofLogWarning() << "no scripts/templates/cmake/CMakeLists.txt in this openFrameworks (CMake support is openFrameworks#8586)";
} else if (!fs::exists(projectDir / "CMakeLists.txt")) {
fs::copy_file(cmakeTemplate, projectDir / "CMakeLists.txt");
}
templateName = "";
}

// emscripten platform: emscripten template (Makefile, config.make, emmake.sh) over the vscode base
if (target == "emscripten") {
recursiveTemplateCopy(getOFRoot() / templatesFolder / "emscripten", projectDir);
if (templateName == "emscripten") templateName = "";
}
if (templateName != "" && !empty(templateName)) {
fs::path templateDir = getOFRoot() / templatesFolder / templateName;
templateDir = normalizePath(templateDir);
Expand Down Expand Up @@ -266,6 +337,7 @@ bool baseProject::save(){
vector <string> lines = fileToStrings(projectDir / "config.make");
std::ofstream saveConfig(projectDir / "config.make");
bool bWroteDefines = false;
bool bWroteWasm = false;

for (auto & str : lines) {
//add the of root path
Expand All @@ -290,13 +362,29 @@ bool baseProject::save(){
saveConfig << "PROJECT_DEFINES = " << ofJoinString(projectDefines, " ") << std::endl;
bWroteDefines = true;
}
}
// emscripten wasm32 / wasm64: 32 is the makefile default, so it leaves the line commented
else if( !emscriptenWasm.empty() && (str.rfind("# PROJECT_EMSCRIPTEN_WASM =", 0) == 0 || str.rfind("PROJECT_EMSCRIPTEN_WASM =", 0) == 0) ){
if (!bWroteWasm) {
saveConfig << (emscriptenWasm == "64" ? "PROJECT_EMSCRIPTEN_WASM = 64" : "# PROJECT_EMSCRIPTEN_WASM = 64") << std::endl;
bWroteWasm = true;
}
}
else if( emscriptenWasm == "32" && str.rfind("EMSCRIPTEN_MEMORY64", 0) == 0 ){
saveConfig << "# " << str << std::endl;
} else {
saveConfig << str << std::endl;
}
}
if (projectDefines.size() && !bWroteDefines && lines.size()) {
saveConfig << "PROJECT_DEFINES = " << ofJoinString(projectDefines, " ") << std::endl;
}
if (emscriptenWasm == "64" && !bWroteWasm && lines.size()) {
saveConfig << "# emscripten: 32 (default) or 64 (wasm64, MEMORY64)" << std::endl;
saveConfig << "PROJECT_EMSCRIPTEN_WASM = 64" << std::endl;
}
saveCMakeLists();

#ifdef OFADDON_OUTPUT_JSON_DEBUG
saveAddonsToJson();
#endif
Expand Down Expand Up @@ -891,3 +979,31 @@ bool baseProject::copyTemplateFile::run() {
}
return true;
}

// OF_ROOT and PROJECT_EMSCRIPTEN_WASM in an openFrameworks app CMakeLists.txt, like config.make
void baseProject::saveCMakeLists() {
fs::path cmakeLists { projectDir / "CMakeLists.txt" };
if (!fs::exists(cmakeLists)) return;
auto lines = fileToStrings(cmakeLists);
bool bOFApp = std::any_of(lines.begin(), lines.end(), [](const std::string & l) { return l.find(OF_CMAKE_INCLUDE) != std::string::npos; });
if (!bOFApp) return;

fs::path root = getOFRoot();
string ofRoot = root.generic_string();
if (projectDir.string().rfind(root.string(), 0) == 0) {
ofRoot = "${CMAKE_CURRENT_SOURCE_DIR}/" + fs::relative(root, projectDir).generic_string();
}
static const std::regex ofRootSet(R"re(^(\s*)set\(OF_ROOT\s+"[^"]*"\))re");
static const std::regex wasmSet(R"re(^\s*set\(\s*PROJECT_EMSCRIPTEN_WASM\b)re");

std::ofstream out(cmakeLists);
for (auto & line : lines) {
if (!emscriptenWasm.empty() && std::regex_search(line, wasmSet)) continue;
if (line.find(OF_CMAKE_INCLUDE) != std::string::npos && emscriptenWasm == "64") {
out << "# emscripten: 32 (default) or 64 (wasm64, MEMORY64)" << std::endl;
out << "set(PROJECT_EMSCRIPTEN_WASM 64)" << std::endl;
}
if (line.find("# emscripten: 32 (default) or 64") != std::string::npos && !emscriptenWasm.empty()) continue;
out << std::regex_replace(line, ofRootSet, "$1set(OF_ROOT \"" + ofRoot + "\")") << std::endl;
}
}
5 changes: 5 additions & 0 deletions commandLine/src/projects/baseProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class baseProject {
// MSYS2 environment (ucrt64 | mingw64 | clang64) - only meaningful for VSCodeProject,
// a no-op everywhere else so callers don't need to know which target this applies to
virtual void setMsys2Environment(const std::string & env) {}
// emscripten wasm32 / wasm64 (-W/--emscripten-wasm), written to config.make PROJECT_EMSCRIPTEN_WASM; empty keeps the project's value
void setEmscriptenWasm(const std::string & bits) { emscriptenWasmOption = bits; }


#ifdef OFADDON_OUTPUT_JSON_DEBUG
Expand Down Expand Up @@ -181,6 +183,9 @@ class baseProject {
std::vector<ofAddon> addons;
std::vector<fs::path> extSrcPaths;
std::vector<std::string> projectDefines; // also written to config.make PROJECT_DEFINES for make builds
std::string emscriptenWasmOption; // from the CLI, empty = keep
std::string emscriptenWasm; // value for this project: "", "32" or "64"
void saveCMakeLists();

//cached addons - if an addon is requested more than once, avoid loading from disk as it's quite slow
std::map<std::string,std::map<std::string, ofAddon>> addonsCache; //indexed by [platform][supplied path]
Expand Down
3 changes: 2 additions & 1 deletion commandLine/src/utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,8 @@ unique_ptr<baseProject> getTargetProject(const string & targ) {
targ == "linux64" ||
targ == "linuxarmv6l" ||
targ == "linuxarmv7l" ||
targ == "linuxaarch64"
targ == "linuxaarch64" ||
targ == "emscripten"
) {
return unique_ptr<VSCodeProject>(new VSCodeProject(targ));
}
Expand Down
27 changes: 22 additions & 5 deletions frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,20 @@ ipcRenderer.on('setSourceExtraPath', (event, [arg, index]) => { // TODO:
//-------------------------------------------
ipcRenderer.on('setGenerateMode', (event, arg) => {
switchGenerateMode(arg);
// new projects start at wasm32; an existing project sends its own value via setEmscriptenWasm
if (arg === 'createMode') {
$('#wasmDropdown').dropdown('set selected', '32');
$('#wasmNote').hide();
}
});

//-------------------------------------------
// existing project's PROJECT_EMSCRIPTEN_WASM, so updating keeps it
ipcRenderer.on('setEmscriptenWasm', (event, bits) => {
$('#wasmDropdown').dropdown('set selected', bits === '64' ? '64' : '32');
$('#wasmNote').toggle(bits === '64');
});

ipcRenderer.on('importProjectSettings', (event, settings) => {
$("#projectPath").val(settings.projectPath);
$("#projectName").val(settings.projectName).trigger('change'); // change triggers addon scanning
Expand Down Expand Up @@ -992,6 +1003,7 @@ function setup() {

$('#rendererDropdown').dropdown();
$('#glDropdown, #webglDropdown, #glesDropdown').dropdown();
$('#wasmDropdown').dropdown({ onChange: (value) => $('#wasmNote').toggle(value === '64') });
$('#rendererDropdown').dropdown('set exactly', 'default');
$('#msys2EnvDropdown').dropdown();
$('#msys2EnvDropdown').dropdown('set exactly', 'ucrt64');
Expand Down Expand Up @@ -1227,7 +1239,8 @@ function generate() {
verbose: bVerbose,
defines: definesArr.join(','),
postBuild: $('#postBuildScript').val().trim(),
msys2Env: $('#msys2EnvField').css('display') !== 'none' ? $('#msys2EnvDropdown').dropdown('get value') : ''
msys2Env: $('#msys2EnvField').css('display') !== 'none' ? $('#msys2EnvDropdown').dropdown('get value') : '',
emscriptenWasm: $('#wasmField').css('display') !== 'none' ? $('#wasmDropdown').dropdown('get value') : ''
};

// console.log(gen);
Expand All @@ -1241,7 +1254,7 @@ function generate() {
// the template pick is cleared in the #projectName change handler instead,
// as soon as the user points at a different project - not here, so a plain
// single generate doesn't wipe the pick you just used
lastGeneratedProject = { projectName: gen.projectName, projectPath: gen.projectPath, templateList: gen.templateList };
lastGeneratedProject = { projectName: gen.projectName, projectPath: gen.projectPath, templateList: gen.templateList, platformList: gen.platformList };
openConsoleForOperation();
ipcRenderer.send('generate', gen);
}
Expand Down Expand Up @@ -1398,7 +1411,9 @@ function updateRendererFieldVisibility() {
$('#rendererField').hide();
}
const selectedTemplates = ($("#templatesDropdown input").val() || '').trim().split(',');
$('#webglField').toggle(!!defaultSettings.advancedMode && selectedTemplates.includes('emscripten'));
const emscripten = selectedTemplates.includes('emscripten') || selectedPlatforms.includes('emscripten');
$('#webglField').toggle(!!defaultSettings.advancedMode && emscripten);
$('#wasmField').toggle(!!defaultSettings.advancedMode && emscripten);
$('#glesField').toggle(!!defaultSettings.advancedMode && selectedPlatforms.some((p) => ['ios', 'macos'].includes(p)));

const glPlatforms = ['osx', 'vs', 'msys2', 'linux', 'linux64', 'linuxarmv6l', 'linuxaarch64', 'vscode'];
Expand Down Expand Up @@ -1458,7 +1473,9 @@ function displayModal(message) {
ipcRenderer.send('openExternal', $(e.currentTarget).prop("href") );
});

const isEmscripten = lastGeneratedProject != null && lastGeneratedProject.templateList.includes('emscripten');
// emscripten template on osx/linux, or the emscripten platform
const isEmscripten = lastGeneratedProject != null
&& (lastGeneratedProject.templateList.includes('emscripten') || (lastGeneratedProject.platformList || []).includes('emscripten'));

$("#IDEButton").hide();
$("#FolderButton").hide();
Expand Down Expand Up @@ -1635,7 +1652,7 @@ function launchInIDE(){
for (let i = 0; i < templatePicked.length; i++){
templateValueArray.push($(templatePicked[i]).attr("data-value"));
}
if (templateValueArray.includes('emscripten')) {
if (templateValueArray.includes('emscripten') || getPlatformList().includes('emscripten')) {
displayModal(`<!--modal-context:none:-->\n<strong>Emscripten</strong><br>${t('modal.emscriptenNoIde')}`);
return;
}
Expand Down
13 changes: 13 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,19 @@
</div>
</div>
</div>
<div class="field" id="wasmField" style="display: none">
<label data-i18n="field.emscriptenWasm">WebAssembly (Emscripten):</label>
<div class="ui selection dropdown" id="wasmDropdown">
<input type="hidden" value="32">
<i class="dropdown icon"></i>
<div class="text" data-i18n="option.wasm32">32-bit (default) (MEMORY32)</div>
<div class="menu">
<div class="item" data-value="32" data-i18n="option.wasm32">32-bit (default) (MEMORY32)</div>
<div class="item" data-value="64" data-i18n="option.wasm64">64-bit (WASM64) (MEMORY64)</div>
</div>
</div>
<p class="ui small grey text" id="wasmNote" style="display: none" data-i18n="note.wasm64">Needs wasm64 libraries: run BITS=64 scripts/emscripten/download_libs.sh (replaces the installed lib/emscripten libraries).</p>
</div>
<div class="field" id="glesField" style="display: none">
<label data-i18n="field.glesVersion">OpenGL ES version (iOS / tvOS):</label>
<div class="ui selection dropdown" id="glesDropdown">
Expand Down
Loading
Loading