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
20 changes: 20 additions & 0 deletions commandLine/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ here's the extended options if you want to experiment. please take are that opt
-v, --verbose run verbose
-t"project_template", --template="project_template" project template
-d, --dryrun don't change files
-f"frameworks", --frameworks="frameworks" Apple system frameworks
(Security,CoreBluetooth)
--system-libs="libraries" Apple system libraries
(sqlite3,z)

run with --help for every option.


**note that on windows, command line flags are written with "/" not "-" and don't have abbreviations, so -r would be /recursive**
Expand Down Expand Up @@ -60,6 +66,20 @@ you can also specify platforms (default platform is inferred) such as:
./projectGenerator -o"pathToOF" -p"ios" pathOfNewIOSProject


## System frameworks and libraries (macOS / iOS / tvOS)

Link SDK frameworks and libraries (sqlite3 = `libsqlite3.tbd`) to a project:

./projectGenerator -o"pathToOF" -p"osx" -f"Security,CoreBluetooth" --system-libs="sqlite3,z" pathToProject

`libsqlite3`, `libsqlite3.tbd`, `-lsqlite3` and `Security.framework` work too. They are saved with the project in `config.make`:

PROJECT_FRAMEWORKS = Security CoreBluetooth
PROJECT_SYSTEM_LIBS = sqlite3 z

and read back on every update, so a plain `./projectGenerator -o"pathToOF" pathToProject` keeps them. The Xcode project gets them in Link Binary With Libraries; the makefiles and CMake read the same lines (`-framework Security` on Apple only, `-lsqlite3` everywhere). Edit `config.make` and update the project, or pass an empty `-f` / `--system-libs=` to remove them.

The GUI shows them as System frameworks / System libraries with Advanced options on and an Apple platform selected (see the help tab).



Expand Down
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 "117"
#define OFPROJECTGENERATOR_MINOR_VERSION "118"
#define OFPROJECTGENERATOR_PATCH_VERSION "0"

#define PG_VERSION (OFPROJECTGENERATOR_MAJOR_VERSION "." OFPROJECTGENERATOR_MINOR_VERSION "." OFPROJECTGENERATOR_PATCH_VERSION)
Expand Down
27 changes: 18 additions & 9 deletions commandLine/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum optionIndex { UNKNOWN,
COMMAND,
BACKUP_PROJECT_FILES,
FRAMEWORKS,
SYSTEMLIBS,
CLEANNAME_DISABLE,
DEFINES,
POSTBUILD,
Expand Down Expand Up @@ -61,7 +62,8 @@ constexpr option::Descriptor usage[] = {
{ COMMAND, 0, "c", "command", option::Arg::None, " --command, -c \truns command" },
{ BACKUP_PROJECT_FILES, 0, "b", "backup", option::Arg::None, " --backup, -b \tbackup project files when replacing with template" },

{ FRAMEWORKS, 0, "f", "frameworks", option::Arg::Optional, " --frameworks, -f \tframeworks list (such as Vision,ARKit)" },
{ FRAMEWORKS, 0, "f", "frameworks", option::Arg::Optional, " --frameworks, -f \tApple system frameworks (such as Security,CoreBluetooth), saved in config.make PROJECT_FRAMEWORKS. Empty removes them" },
{ SYSTEMLIBS, 0, "", "system-libs", option::Arg::Optional, " --system-libs \tApple system libraries (such as sqlite3,z = libsqlite3.tbd, libz.tbd), saved in config.make PROJECT_SYSTEM_LIBS. Empty removes them" },

{ CLEANNAME_DISABLE, 0, "n", "cleanname", option::Arg::Optional, " --cleanname, -f \tcleanname" },

Expand Down Expand Up @@ -98,6 +100,9 @@ vector<string> addons;
vector<fs::path> srcPaths;
vector<string> targets;
vector<string> frameworks;
bool bFrameworksPassedIn = false;
vector<string> systemLibs;
bool bSystemLibsPassedIn = false;
vector<string> defines;
string postBuildScript;
string emscriptenWasm; // empty keeps the project's config.make value
Expand Down Expand Up @@ -276,6 +281,7 @@ void updateProject(const fs::path & path, const string & target, bool bConsiderP
project->setMsys2Environment(msys2Env);
project->setEmscriptenWasm(emscriptenWasm);
project->setAppVersion(appVersion, appBuild);
project->setSystemFrameworks(frameworks, bFrameworksPassedIn, systemLibs, bSystemLibsPassedIn);
project->create(path, templateName);

if (bConsiderParameterAddons && bAddonsPassedIn) {
Expand All @@ -286,9 +292,7 @@ void updateProject(const fs::path & path, const string & target, bool bConsiderP
ofLogNotice() << "parsing addons.make";
project->parseAddons();
}
for (auto & f : frameworks) {
project->addFramework(f, "Frameworks", true);
}
project->addSystemFrameworks();

// all build configs (visualStudioProject overrides addProjectDefine for Debug + Release)
for (auto & d : defines) {
Expand Down Expand Up @@ -624,10 +628,16 @@ int pgMain(int argc, char ** argv) {
#endif

if (options[FRAMEWORKS].count() > 0) {
bAddonsPassedIn = true; // could be empty
bFrameworksPassedIn = true; // could be empty
if (options[FRAMEWORKS].arg != NULL) {
frameworks = ofSplitString(options[FRAMEWORKS].arg, ",", true, true);
// cout << "frameworks " << options[FRAMEWORKS].arg << endl;
}
}

if (options[SYSTEMLIBS].count() > 0) {
bSystemLibsPassedIn = true; // could be empty
if (options[SYSTEMLIBS].arg != NULL) {
systemLibs = ofSplitString(options[SYSTEMLIBS].arg, ",", true, true);
}
}

Expand Down Expand Up @@ -807,6 +817,7 @@ int pgMain(int argc, char ** argv) {
project->setMsys2Environment(msys2Env);
project->setEmscriptenWasm(emscriptenWasm);
project->setAppVersion(appVersion, appBuild);
project->setSystemFrameworks(frameworks, bFrameworksPassedIn, systemLibs, bSystemLibsPassedIn);
project->create(projectPath, templateName);
if(bAddonsPassedIn){
for (auto & addon : addons) {
Expand All @@ -815,9 +826,7 @@ int pgMain(int argc, char ** argv) {
}else{
project->parseAddons();
}
for (auto & f : frameworks) {
project->addFramework(f, "Frameworks", true);
}
project->addSystemFrameworks();

for (auto & d : defines) {
project->addProjectDefine(d);
Expand Down
115 changes: 115 additions & 0 deletions commandLine/src/projects/baseProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,51 @@ static std::string readEmscriptenWasm(const fs::path & configMake) {
return bits;
}

// space separated list from config.make, VAR = a b / VAR += c
static std::vector<std::string> readMakeList(const fs::path & configMake, const std::string & name) {
std::vector<std::string> values;
if (!fs::exists(configMake)) return values;
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));
bool append = !var.empty() && var.back() == '+';
if (!var.empty() && (var.back() == '?' || var.back() == '+' || var.back() == ':')) var = ofTrim(var.substr(0, var.size() - 1));
if (var != name) continue;
if (!append) values.clear();
for (auto & v : ofSplitString(ofTrim(config.substr(eq + 1)), " ", true, true)) values.emplace_back(v);
}
return values;
}

// Security.framework -> Security
static std::string cleanFrameworkName(std::string name) {
name = ofTrim(name);
if (name.size() > 10 && name.substr(name.size() - 10) == ".framework") name = name.substr(0, name.size() - 10);
return name;
}

// -lsqlite3 / libsqlite3 / libsqlite3.tbd / libsqlite3.dylib -> sqlite3
static std::string cleanSystemLibName(std::string name) {
name = ofTrim(name);
if (name.rfind("-l", 0) == 0) name = name.substr(2);
for (std::string ext : { ".tbd", ".dylib" }) {
if (name.size() > ext.size() && name.substr(name.size() - ext.size()) == ext) name = name.substr(0, name.size() - ext.size());
}
if (name.rfind("lib", 0) == 0 && name.size() > 3) name = name.substr(3);
return name;
}

static bool isSystemLibName(const std::string & name) {
return name.rfind("-l", 0) == 0 || name.rfind("lib", 0) == 0 || ofIsStringInString(name, ".tbd") || ofIsStringInString(name, ".dylib");
}

static void addUnique(std::vector<std::string> & list, const std::string & value) {
if (!value.empty() && std::find(list.begin(), list.end(), value) == list.end()) list.emplace_back(value);
}

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)
Expand Down Expand Up @@ -252,6 +297,18 @@ bool baseProject::create(const fs::path & _path, string templateName){
ofLogNotice() << "{ \"emscriptenWasm\": \"" << emscriptenWasm << "\" }";
}

systemFrameworks.clear();
systemLibs.clear();
for (auto & f : systemFrameworksPassed ? systemFrameworksOption : readMakeList(projectDir / "config.make", "PROJECT_FRAMEWORKS")) {
if (isSystemLibName(f)) addUnique(systemLibs, cleanSystemLibName(f));
else addUnique(systemFrameworks, cleanFrameworkName(f));
}
for (auto & l : systemLibsPassed ? systemLibsOption : readMakeList(projectDir / "config.make", "PROJECT_SYSTEM_LIBS")) {
addUnique(systemLibs, cleanSystemLibName(l));
}
if (systemFrameworks.size()) ofLogNotice() << "{ \"systemFrameworks\": \"" << ofJoinString(systemFrameworks, " ") << "\" }";
if (systemLibs.size()) ofLogNotice() << "{ \"systemLibs\": \"" << ofJoinString(systemLibs, " ") << "\" }";

// app version / build: config.make first, then CMakeLists, Xcode, Android; the CLI value wins
{
std::vector<std::pair<std::string, std::pair<std::string, std::string>>> found {
Expand Down Expand Up @@ -427,6 +484,28 @@ bool baseProject::save(){
bool bWroteWasm = false;
bool bWroteAppVersion = false;
bool bWroteAppBuild = false;
bool bWroteFrameworks = false;
bool bWroteSystemLibs = false;
auto isMakeVar = [](const std::string & line, const std::string & name) {
auto config = ofTrim(line);
if (config.rfind("#", 0) == 0) config = ofTrim(config.substr(1));
if (config.rfind(name, 0) != 0) return false;
auto rest = ofTrim(config.substr(name.size()));
return rest.rfind("=", 0) == 0 || rest.rfind("+=", 0) == 0 || rest.rfind(":=", 0) == 0 || rest.rfind("?=", 0) == 0;
};
// the list on the first line, commented when empty, later += lines are folded in
auto writeMakeList = [&](const std::string & line, const std::string & name, const std::vector<std::string> & values, bool & bWrote) {
if (bWrote) {
if (ofTrim(line).rfind("#", 0) == 0) saveConfig << line << std::endl;
return;
}
if (values.empty()) {
saveConfig << (ofTrim(line).rfind("#", 0) == 0 ? line : "# " + name + " =") << std::endl;
} else {
saveConfig << name << " = " << ofJoinString(values, " ") << std::endl;
}
bWrote = true;
};

for (auto & str : lines) {
//add the of root path
Expand Down Expand Up @@ -472,6 +551,12 @@ bool baseProject::save(){
bWroteAppBuild = true;
}
}
else if( isMakeVar(str, "PROJECT_FRAMEWORKS") ){
writeMakeList(str, "PROJECT_FRAMEWORKS", systemFrameworks, bWroteFrameworks);
}
else if( isMakeVar(str, "PROJECT_SYSTEM_LIBS") ){
writeMakeList(str, "PROJECT_SYSTEM_LIBS", systemLibs, bWroteSystemLibs);
}
else if( emscriptenWasm == "32" && str.rfind("EMSCRIPTEN_MEMORY64", 0) == 0 ){
saveConfig << "# " << str << std::endl;
} else {
Expand All @@ -490,6 +575,12 @@ bool baseProject::save(){
if (!bWroteAppVersion) saveConfig << "APP_VERSION = " << appVersion << std::endl;
if (!bWroteAppBuild) saveConfig << "APP_BUILD = " << appBuild << std::endl;
}
if ((systemFrameworks.size() && !bWroteFrameworks) || (systemLibs.size() && !bWroteSystemLibs)) {
if (lines.size()) saveConfig << std::endl;
saveConfig << "# system frameworks (Security) and libraries (sqlite3 = libsqlite3.tbd / -lsqlite3)" << std::endl;
if (systemFrameworks.size() && !bWroteFrameworks) saveConfig << "PROJECT_FRAMEWORKS = " << ofJoinString(systemFrameworks, " ") << std::endl;
if (systemLibs.size() && !bWroteSystemLibs) saveConfig << "PROJECT_SYSTEM_LIBS = " << ofJoinString(systemLibs, " ") << std::endl;
}
saveConfig.close();
saveCMakeLists();
saveAppVersionFiles();
Expand Down Expand Up @@ -1010,6 +1101,30 @@ void baseProject::parseConfigMake(){
}
}

void baseProject::setSystemFrameworks(const std::vector<std::string> & frameworks, bool frameworksPassed, const std::vector<std::string> & libs, bool libsPassed) {
// "Security CoreBluetooth" is two, names have no spaces
auto splitSpaces = [](const std::vector<std::string> & list) {
std::vector<std::string> out;
for (auto & l : list) {
for (auto & v : ofSplitString(l, " ", true, true)) out.emplace_back(v);
}
return out;
};
systemFrameworksOption = splitSpaces(frameworks);
systemFrameworksPassed = frameworksPassed;
systemLibsOption = splitSpaces(libs);
systemLibsPassed = libsPassed;
}

void baseProject::addSystemFrameworks() {
for (auto & f : systemFrameworks) {
addFramework(f, "Frameworks", true);
}
for (auto & l : systemLibs) {
addSystemLibrary(l);
}
}

void baseProject::recursiveTemplateCopy(const fs::path & srcDir, const fs::path & destDir){
if (recursiveCopy(srcDir, destDir)) {
fs::path templateFile = destDir / "template.config";
Expand Down
9 changes: 9 additions & 0 deletions commandLine/src/projects/baseProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ class baseProject {
bool bOverwrite = true;

virtual void addFramework(const fs::path & path, const fs::path & folder, bool isRelativeToSDK = false){};
// SDK library like sqlite3 = usr/lib/libsqlite3.tbd (Xcode only)
virtual void addSystemLibrary(const std::string & name){};

// system frameworks / libraries (-f / --system-libs), kept in config.make PROJECT_FRAMEWORKS / PROJECT_SYSTEM_LIBS
void setSystemFrameworks(const std::vector<std::string> & frameworks, bool frameworksPassed, const std::vector<std::string> & libs, bool libsPassed);
void addSystemFrameworks();

// public entry point for project-level preprocessor defines (e.g. -D/--defines on the
// CLI, or a GUI-driven renderer choice) - addDefine() itself stays protected since it's
Expand Down Expand Up @@ -185,6 +191,9 @@ class baseProject {
std::vector<fs::path> extSrcPaths;
std::vector<std::string> projectDefines; // also written to config.make PROJECT_DEFINES for make builds
std::vector<std::string> missingAddons; // not found, still written to addons.make (#258)
std::vector<std::string> systemFrameworks, systemLibs; // value for this project
std::vector<std::string> systemFrameworksOption, systemLibsOption; // from the CLI
bool systemFrameworksPassed = false, systemLibsPassed = false; // false = keep the project's
std::string emscriptenWasmOption; // from the CLI, empty = keep
std::string emscriptenWasm; // value for this project: "", "32" or "64"
void saveCMakeLists();
Expand Down
11 changes: 11 additions & 0 deletions commandLine/src/projects/xcodeProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,17 @@ void xcodeProject::addFramework(const fs::path & path, const fs::path & folder,
}
}

void xcodeProject::addSystemLibrary(const std::string & name) {
ofLogVerbose() << "Adding system library " << name;
addCommand("# ----- addSystemLibrary " + name);

fileProperties fp;
fp.absolute = false;
fp.isRelativeToSDK = true;
fp.linkBinaryWithLibraries = true;
addFile(fs::path { "usr/lib/lib" + name + ".tbd" }, "Frameworks", fp);
}

void xcodeProject::addDylib(const fs::path & path, const fs::path & folder) {
// alert( "xcodeProject::addDylib " + ofPathToString(path) , 33);

Expand Down
2 changes: 2 additions & 0 deletions commandLine/src/projects/xcodeProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class xcodeProject : public baseProject {

void addCompileFlagsForMMFile(const fs::path & srcFile);
void addFramework(const fs::path & path, const fs::path & folder, bool isRelativeToSDK = false) override;
void addSystemLibrary(const std::string & name) override;
void addXCFramework(const fs::path & path, const fs::path & folder);
void addDylib(const fs::path & path, const fs::path & folder);

Expand Down Expand Up @@ -125,6 +126,7 @@ class xcodeProject : public baseProject {
{ ".framework" , "wrapper.framework" },
{ ".xcframework" , "wrapper.xcframework" },
{ ".dylib" , "compiled.mach-o.dylib" },
{ ".tbd" , "sourcecode.text-based-dylib-definition" },

{ ".cpp" , "sourcecode.cpp.cpp" },
{ ".c" , "sourcecode.cpp.c" },
Expand Down
15 changes: 14 additions & 1 deletion frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ ipcRenderer.on('setGenerateMode', (event, arg) => {
$('#appVersion').val('');
$('#appBuild').val('');
$('#appVersionNote').hide();
$('#systemFrameworks').val('');
$('#systemLibs').val('');
}
});

Expand All @@ -230,6 +232,13 @@ ipcRenderer.on('setAppVersion', (event, { version, build, differs }) => {
$('#appVersionNote').text(note).toggle(!!defaultSettings.advancedMode && note.length > 0);
});

//-------------------------------------------
// existing project's config.make PROJECT_FRAMEWORKS / PROJECT_SYSTEM_LIBS, so updating keeps them
ipcRenderer.on('setSystemFrameworks', (event, { frameworks, libs }) => {
$('#systemFrameworks').val((frameworks || []).join(','));
$('#systemLibs').val((libs || []).join(','));
});

//-------------------------------------------
// existing project's PROJECT_EMSCRIPTEN_WASM, so updating keeps it
ipcRenderer.on('setEmscriptenWasm', (event, bits) => {
Expand Down Expand Up @@ -1276,7 +1285,10 @@ function generate() {
msys2Env: $('#msys2EnvField').css('display') !== 'none' ? $('#msys2EnvDropdown').dropdown('get value') : '',
emscriptenWasm: $('#wasmField').css('display') !== 'none' ? $('#wasmDropdown').dropdown('get value') : '',
appVersion: $('#appVersion').val().trim(),
appBuild: $('#appBuild').val().trim()
appBuild: $('#appBuild').val().trim(),
// only for Apple targets; hidden = keep the project's config.make values
systemFrameworks: $('#systemFrameworksField').css('display') !== 'none' ? $('#systemFrameworks').val().split(/[\s,]+/).filter(Boolean) : null,
systemLibs: $('#systemFrameworksField').css('display') !== 'none' ? $('#systemLibs').val().split(/[\s,]+/).filter(Boolean) : null
};

// console.log(gen);
Expand Down Expand Up @@ -1469,6 +1481,7 @@ function updateRendererFieldVisibility() {
// advanced only; hidden fields keep the project's values, so updating still keeps them
$('#appVersionField').css('display', defaultSettings.advancedMode ? 'flex' : 'none');
$('#appVersionNote').toggle(!!defaultSettings.advancedMode && $('#appVersionNote').text().length > 0);
$('#systemFrameworksField').css('display', defaultSettings.advancedMode && selectedPlatforms.some((p) => ['osx', 'ios', 'macos', 'tvos'].includes(p)) ? 'flex' : 'none');

const glPlatforms = ['osx', 'vs', 'msys2', 'linux', 'linux64', 'linuxarmv6l', 'linuxarmv7l', 'linuxaarch64', 'vscode'];
$('#glField').toggle(!!defaultSettings.advancedMode && selectedPlatforms.some((p) => glPlatforms.includes(p)));
Expand Down
Loading
Loading