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 "122"
#define OFPROJECTGENERATOR_MINOR_VERSION "124"
#define OFPROJECTGENERATOR_PATCH_VERSION "0"

#define PG_VERSION (OFPROJECTGENERATOR_MAJOR_VERSION "." OFPROJECTGENERATOR_MINOR_VERSION "." OFPROJECTGENERATOR_PATCH_VERSION)
Expand Down
26 changes: 22 additions & 4 deletions commandLine/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ fs::path generatorPath;
fs::path ofPath;
vector<string> addons;
vector<fs::path> srcPaths;
bool bSrcPathsPassedIn = false; // false = keep the project's config.make PROJECT_EXTERNAL_SOURCE_PATHS
vector<string> targets;
vector<string> frameworks;
bool bFrameworksPassedIn = false;
Expand Down Expand Up @@ -306,6 +307,7 @@ void updateProject(const fs::path & path, const string & target, bool bConsiderP
project->addProjectAfterRule(postBuildScript);
}

if (!bSrcPathsPassedIn) project->addSavedSrcPaths();
for (auto & srcPath : srcPaths) {
project->addSrcRecursively(srcPath);
}
Expand Down Expand Up @@ -478,20 +480,22 @@ int pgMain(int argc, char ** argv) {
argv += (argc > 0); // skip program name argv[0] if present

// optionparser only takes attached values (-posx, --platforms=osx); join -p osx / --platforms osx,
// but leave the last argument as the project path (-f <path> is an empty -f)
// but leave the last argument as the project path: -t"" <path> (scripts, the GUI) is an empty -t
static const std::string valueShort { "paotsmfDPkW" };
static const std::vector<std::string> valueLong { "platforms", "addons", "ofPath", "template", "source", "ofmenu", "frameworks", "system-libs", "defines", "postbuild", "msys2env", "emscripten-wasm", "app-version", "app-build", "bundle-id" };
std::vector<std::string> joinedArgs;
std::string platformBeforePath;
for (int i = 0; i < argc; i++) {
std::string a { argv[i] };
bool isValueOption = (a.size() == 2 && a[0] == '-' && valueShort.find(a[1]) != std::string::npos)
|| (a.rfind("--", 0) == 0 && std::find(valueLong.begin(), valueLong.end(), a.substr(2)) != valueLong.end());
// only -f / --frameworks / --system-libs mean something empty (remove), so -f <path> keeps the path
bool emptyMeansRemove = a == "-f" || a == "--frameworks" || a == "--system-libs";
if (isValueOption && i + 1 < argc && argv[i + 1][0] != '-' && (i + 2 < argc || !emptyMeansRemove)) {
bool keyword = a == "-m" || a == "--ofmenu"; // status / update-libs, no project path after it
if (isValueOption && i + 1 < argc && argv[i + 1][0] != '-' && (i + 2 < argc || keyword)) {
joinedArgs.emplace_back(a + (a.size() == 2 ? "" : "=") + argv[i + 1]);
i++;
} else {
// -p osx with no project path: osx would be taken as the project
if ((a == "-p" || a == "--platforms") && i + 2 == argc && argv[i + 1][0] != '-') platformBeforePath = argv[i + 1];
joinedArgs.emplace_back(a);
}
}
Expand Down Expand Up @@ -650,6 +654,7 @@ int pgMain(int argc, char ** argv) {

// Additional Src Paths
if (options[SRCEXTERNAL].count() > 0) {
bSrcPathsPassedIn = true; // could be empty
if (options[SRCEXTERNAL].arg != NULL) {
string srcString(options[SRCEXTERNAL].arg);
// TODO: TEST
Expand Down Expand Up @@ -758,8 +763,20 @@ int pgMain(int argc, char ** argv) {
messageError("Missing project path");
return EXIT_USAGE;
}
if (!platformBeforePath.empty() && projectName == platformBeforePath && getTargetProject(platformBeforePath) && !fs::exists(fs::current_path() / projectName)) {
printHelp();
consoleSpace();
messageError("Missing project path (\"" + projectName + "\" after -p is the platform) - eg -p" + projectName + " path/to/myApp");
return EXIT_USAGE;
}

fs::path projectPath = normalizePath(fs::weakly_canonical(fs::current_path() / projectName));
// -s relative to here, unless it's relative to the project (config.make, the GUI)
for (auto & s : srcPaths) {
if (s.is_relative() && !fs::exists(projectPath / s) && fs::exists(fs::current_path() / s)) {
s = normalizePath(fs::weakly_canonical(fs::current_path() / s));
}
}
fs::path projectNamePath = projectPath.filename();
projectName = projectNamePath.string();

Expand Down Expand Up @@ -898,6 +915,7 @@ int pgMain(int argc, char ** argv) {
project->addProjectAfterRule(postBuildScript);
}

if (!bSrcPathsPassedIn) project->addSavedSrcPaths();
for (auto & s : srcPaths) {
project->addSrcRecursively(s);
}
Expand Down
33 changes: 28 additions & 5 deletions commandLine/src/projects/baseProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ bool baseProject::create(const fs::path & _path, string templateName){
ofLogNotice() << "{ \"emscriptenWasm\": \"" << emscriptenWasm << "\" }";
}

savedExtSrcPaths = readMakeList(projectDir / "config.make", "PROJECT_EXTERNAL_SOURCE_PATHS");
systemFrameworks.clear();
systemLibs.clear();
for (auto & f : systemFrameworksPassed ? systemFrameworksOption : readMakeList(projectDir / "config.make", "PROJECT_FRAMEWORKS")) {
Expand Down Expand Up @@ -563,6 +564,7 @@ bool baseProject::save(){
bool bWroteFrameworks = false;
bool bWroteSystemLibs = false;
bool bWroteBundleId = false;
bool bWroteExtSrcPaths = 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));
Expand Down Expand Up @@ -594,12 +596,14 @@ bool baseProject::save(){
}
saveConfig << "OF_ROOT = " << path.generic_string() << std::endl;
}
// replace this section with our external paths
else if( extSrcPaths.size() && str.rfind("# PROJECT_EXTERNAL_SOURCE_PATHS =", 0) == 0 ){
for(std::size_t d = 0; d < extSrcPaths.size(); d++){
ofLog(OF_LOG_VERBOSE) << " adding PROJECT_EXTERNAL_SOURCE_PATHS to config" << extSrcPaths[d].generic_string() << std::endl;
saveConfig << "PROJECT_EXTERNAL_SOURCE_PATHS" << (d == 0 ? " = " : " += ") << extSrcPaths[d].generic_string() << std::endl;
// external source paths, relative to the project like the makefiles read them; replaces an old value too
else if( isMakeVar(str, "PROJECT_EXTERNAL_SOURCE_PATHS") ){
std::vector<std::string> paths;
for (auto & p : extSrcPaths) {
fs::path rel = p.is_absolute() ? fs::path(p).lexically_relative(fs::current_path()) : p;
paths.emplace_back((rel.empty() ? p : rel).generic_string());
}
writeMakeList(str, "PROJECT_EXTERNAL_SOURCE_PATHS", paths, bWroteExtSrcPaths);
}
// make builds (emscripten, linux, msys2) only see defines through config.make
else if( projectDefines.size() && (str.rfind("# PROJECT_DEFINES =", 0) == 0 || str.rfind("PROJECT_DEFINES =", 0) == 0) ){
Expand Down Expand Up @@ -655,6 +659,14 @@ bool baseProject::save(){
if (!bWroteAppVersion) saveConfig << "APP_VERSION = " << appVersion << std::endl;
if (!bWroteAppBuild) saveConfig << "APP_BUILD = " << appBuild << std::endl;
}
if (extSrcPaths.size() && !bWroteExtSrcPaths) {
if (lines.size()) saveConfig << std::endl;
saveConfig << "# external source folders, relative to the project" << std::endl;
for (std::size_t d = 0; d < extSrcPaths.size(); d++) {
fs::path rel = extSrcPaths[d].is_absolute() ? extSrcPaths[d].lexically_relative(fs::current_path()) : extSrcPaths[d];
saveConfig << "PROJECT_EXTERNAL_SOURCE_PATHS" << (d == 0 ? " = " : " += ") << (rel.empty() ? extSrcPaths[d] : rel).generic_string() << 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;
Expand Down Expand Up @@ -1202,6 +1214,17 @@ void baseProject::setSystemFrameworks(const std::vector<std::string> & framework
systemLibsPassed = libsPassed;
}

void baseProject::addSavedSrcPaths() {
// the project folder is the working directory here, like config.make's relative paths
for (auto & p : savedExtSrcPaths) {
if (fs::exists(p)) {
addSrcRecursively(p);
} else {
ofLogWarning() << "config.make PROJECT_EXTERNAL_SOURCE_PATHS " << p << " doesn't exist - skipped";
}
}
}

void baseProject::addSystemFrameworks() {
for (auto & f : systemFrameworks) {
addFramework(f, "Frameworks", true);
Expand Down
3 changes: 3 additions & 0 deletions commandLine/src/projects/baseProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class baseProject {
// 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();
// config.make PROJECT_EXTERNAL_SOURCE_PATHS, when no -s was given
void addSavedSrcPaths();

// 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 @@ -191,6 +193,7 @@ class baseProject {

std::vector<ofAddon> addons;
std::vector<fs::path> extSrcPaths;
std::vector<std::string> savedExtSrcPaths; // config.make PROJECT_EXTERNAL_SOURCE_PATHS, read before the template copies
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
Expand Down
5 changes: 2 additions & 3 deletions frontend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1885,9 +1885,8 @@ function generateFunction(event, generate) {
args.push(`-p${platformList.join(",")}`);
}

if (sourcePath != null && sourcePath.length > 0) {
args.push(`-s${sourcePath}`);
}
// always: an empty -s removes the project's external source folders (the field shows config.make's)
args.push(`-s${sourcePath || ''}`);

if (templateList != null) {
args.push(`-t${templateList.join(",")}`);
Expand Down
4 changes: 2 additions & 2 deletions frontend/npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "projectGenerator",
"productName": "projectGenerator",
"version": "0.117.0",
"version": "0.119.0",
"description": "Build electron GUI openFrameworks projectGenerator",
"license": "MIT",
"main": "index.js",
Expand Down
167 changes: 167 additions & 0 deletions scripts/test_cmdline_args.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,31 @@ expect_output() {
echo "$OUT" | grep -qE "$1" || fail "output has no '$1'"
}

expect_file() {
[ -e "$1" ] || fail "${1#$OF/} missing"
}

expect_in_file() {
tr -d '\r' < "$1" 2>/dev/null | grep -qF -- "$2" || fail "${1#$OF/} has no '$2'"
}

# Xcode / Visual Studio list the sources; make projects read them from config.make
project_sources_file() {
if [ "$XCODE" = 1 ]; then echo "$APP_DIR/myApp.xcodeproj/project.pbxproj"; elif [ "$PLATFORM" = vs ]; then echo "$APP_DIR/myApp.vcxproj"; fi
}

expect_src_in_project() {
local f
f="$(project_sources_file)"
[ -z "$f" ] || expect_in_file "$f" "$1"
}

expect_src_not_in_project() {
local f
f="$(project_sources_file)"
[ -z "$f" ] || ! tr -d '\r' < "$f" | grep -qF -- "$1" || fail "${f#$OF/} still has $1"
}

expect_pbxproj() {
[ "$XCODE" = 1 ] || return 0
grep -q "$1" "$APP_DIR/myApp.xcodeproj/project.pbxproj" 2>/dev/null || fail "project.pbxproj has no $1"
Expand Down Expand Up @@ -180,6 +205,18 @@ pg -o .. -p "$PLATFORM" -a ofxGui -D A=1 -P "echo done" -s myApps/pgArgTests/sha
expect_exit 0; expect_updated; expect_no_stray
grep -q ofxGui "$APP_DIR/addons.make" 2>/dev/null || fail "addons.make has no ofxGui"

start "empty values before the path, as OF's CI scripts: -a\"\" -p\"$PLATFORM\" -t\"\" path (was: path taken as the template)"
pg -o"$OF" -v -a"" -p"$PLATFORM" -t"" "$APP"
expect_exit 0; expect_updated; expect_no_stray

start "bare -t right before the path, as the GUI with no template (was: path taken as the template)"
pg -o.. -a -p"$PLATFORM" -t "$APP"
expect_exit 0; expect_updated; expect_no_stray

start "empty separate values: -a \"\" -t \"\" path"
pg -o.. -p"$PLATFORM" -a "" -t "" "$APP"
expect_exit 0; expect_updated; expect_no_stray

start "project path only (host platform, OF path from -o)"
pg -o.. "$APP"
expect_exit 0; expect_no_stray
Expand Down Expand Up @@ -234,6 +271,136 @@ pg -o.. -p"$PLATFORM" -r myApps/pgArgTests
expect_exit 0; expect_updated; expect_no_stray
[ -e "$TEST_DIR/other/${PROJECT_FILE/myApp/other}" ] || fail "other/${PROJECT_FILE/myApp/other} not written"

# ---------------------------------------------------------------- how the GUI and openFrameworks' scripts call it

# frontend/index.js generateFunction: -v -o -a -p -s -t [-D -P -k -W --app-*] [-f --system-libs] path
start "GUI generate, no addons / template / source: -a<space> -s -t path"
pg -v -o"$OF" "-a " -p"$PLATFORM" -s -t "$APP"
expect_exit 0; expect_updated; expect_no_stray

start "GUI generate with addons, defines, post-build, version"
pg -v -o"$OF" -a"ofxGui,ofxOsc" -p"$PLATFORM" -s -t -D"A=1,B" -P"echo gui-postbuild" --app-version=2.0 --app-build=7 "$APP"
expect_exit 0; expect_updated; expect_no_stray
expect_in_file "$APP_DIR/addons.make" "ofxOsc"

# frontend/index.js updateFunction (update multiple): -r -v -o -p [-t] folder
start "GUI update multiple: -r -v -o -p folder"
mkdir -p "$TEST_DIR/other/src" && cp "$APP_DIR/src/"* "$TEST_DIR/other/src/"
pg -r -v -o"$OF" -p"$PLATFORM" myApps/pgArgTests
expect_exit 0; expect_updated; expect_no_stray

# scripts/dev/create_package.sh, scripts/osx/snapshotAllExamples.sh
start "openFrameworks create_package: --recursive -p -o folder"
mkdir -p "$TEST_DIR/other/src" && cp "$APP_DIR/src/"* "$TEST_DIR/other/src/"
pg --recursive -p"$PLATFORM" -o"$OF" "$TEST_DIR"
expect_exit 0; expect_updated; expect_no_stray

# scripts/ci/cmake/build.sh
if [ -f "$OF/scripts/templates/cmake/CMakeLists.txt" ]; then
start "openFrameworks cmake build.sh: -o -t\"cmake\" -p path"
pg -o"$OF" -t"cmake" -p"$PLATFORM" "$APP_DIR"
expect_exit 0; expect_file "$APP_DIR/CMakeLists.txt"; expect_no_stray
fi

# ---------------------------------------------------------------- project paths

start "spaces in the project name"
mkdir -p "$TEST_DIR/my App/src" && cp "$APP_DIR/src/"* "$TEST_DIR/my App/src/"
pg -o.. -p"$PLATFORM" "myApps/pgArgTests/my App"
expect_exit 0; expect_file "$TEST_DIR/my App/${PROJECT_FILE/myApp/my App}"; expect_no_stray

start "trailing slash and ./ in the project path"
pg -o.. -p"$PLATFORM" "./$APP/"
expect_exit 0; expect_updated; expect_no_stray

start "project path relative to apps/myApps (a name only)"
mkdir -p "$TEST_DIR/../pgArgTestsByName/src" && cp "$APP_DIR/src/"* "$TEST_DIR/../pgArgTestsByName/src/"
pg -o"$OF" -p"$PLATFORM" pgArgTestsByName
[ -e "$RUN_DIR/myApps/pgArgTestsByName/${PROJECT_FILE/myApp/pgArgTestsByName}" ] || [ -e "$RUN_DIR/pgArgTestsByName/${PROJECT_FILE/myApp/pgArgTestsByName}" ] || fail "pgArgTestsByName not generated"
rm -rf "$RUN_DIR/myApps/pgArgTestsByName" "$RUN_DIR/pgArgTestsByName"
expect_no_stray

# ---------------------------------------------------------------- addons

start "missing addon is kept in addons.make"
pg -o.. -p"$PLATFORM" -a"ofxGui,ofxDoesNotExist" "$APP"
expect_exit 0; expect_updated; expect_output "addon not found: ofxDoesNotExist"
expect_in_file "$APP_DIR/addons.make" "ofxDoesNotExist"

start "addons with spaces and duplicates"
pg -o.. -p"$PLATFORM" -a"ofxGui, ofxOsc,ofxGui" "$APP"
expect_exit 0
[ "$(tr -d '\r' < "$APP_DIR/addons.make" | grep -cx ofxGui)" = 1 ] || fail "addons.make should list ofxGui once"
expect_in_file "$APP_DIR/addons.make" "ofxOsc"

start "addons.make comments and #url of a missing addon are kept"
printf 'ofxGui\nofxMissingOne#https://github.com/example/ofxMissingOne\n' > "$APP_DIR/addons.make"
pg -o.. -p"$PLATFORM" "$APP"
expect_exit 0; expect_in_file "$APP_DIR/addons.make" "ofxMissingOne#https://github.com/example/ofxMissingOne"

start "no addons and no addons.make: none written"
pg -o.. -p"$PLATFORM" "$APP"
expect_exit 0; [ ! -e "$APP_DIR/addons.make" ] || fail "empty addons.make written"

# ---------------------------------------------------------------- external sources (-s)

mkshared() {
mkdir -p "$TEST_DIR/shared" && printf 'int sharedFn() { return 1; }\n' > "$TEST_DIR/shared/sharedSource.cpp"
}

start "-s relative to the current folder (was: silently nothing)"
mkshared
pg -o.. -p"$PLATFORM" -s myApps/pgArgTests/shared "$APP"
expect_exit 0; expect_config PROJECT_EXTERNAL_SOURCE_PATHS "../shared"
expect_src_in_project "sharedSource.cpp"

start "-s relative to the project"
mkshared
pg -o.. -p"$PLATFORM" -s ../shared "$APP"
expect_exit 0; expect_config PROJECT_EXTERNAL_SOURCE_PATHS "../shared"

start "-s absolute, written relative to the project"
mkshared
pg -o.. -p"$PLATFORM" -s "$TEST_DIR/shared" "$APP"
expect_exit 0; expect_config PROJECT_EXTERNAL_SOURCE_PATHS "../shared"

start "external sources kept on update without -s, empty -s removes them (was: dropped / stale)"
mkshared
pg -o.. -p"$PLATFORM" -s ../shared "$APP"
pg -o.. -p"$PLATFORM" "$APP"
expect_exit 0; expect_config PROJECT_EXTERNAL_SOURCE_PATHS "../shared"
expect_src_in_project "sharedSource.cpp"
pg -o.. -p"$PLATFORM" -s -t "$APP"
expect_exit 0; expect_no_config PROJECT_EXTERNAL_SOURCE_PATHS
expect_src_not_in_project "sharedSource.cpp"

# ---------------------------------------------------------------- other options

start "-t vscode adds VS Code to the platform (#476)"
pg -o.. -p"$PLATFORM" -tvscode "$APP"
expect_exit 0; expect_updated; expect_file "$APP_DIR/.vscode"

start "-P post-build script lands in the project"
pg -o.. -p"$PLATFORM" -P "echo pg-postbuild-test" "$APP"
expect_exit 0
if [ "$XCODE" = 1 ]; then expect_pbxproj "pg-postbuild-test"; elif [ "$PLATFORM" = vs ]; then expect_in_file "$APP_DIR/myApp.vcxproj" "pg-postbuild-test"; fi

start "-k bad MSYS2 environment warns"
pg -o.. -pmsys2 -k bogus "$APP"
expect_exit 0; expect_output "unknown msys2 environment bogus"

start "-w / -i / --getofpath"
pg -w
expect_exit 0; expect_output "openFrameworks projectGenerator"
pg -i
expect_exit 0; expect_output "ofHostPlatform"
pg -o.. --getofpath
expect_exit 0; expect_output '"ofPath"'

start "-l lists templates"
pg -o.. -p"$PLATFORM" -l "$APP"
expect_exit 0

# ---------------------------------------------------------------- system frameworks / libraries

start "frameworks: commas"
Expand Down
Loading