33 #include "../../rapidxml/wrapper/RapidXmlReader.h"
36 #include <boost/interprocess/managed_shared_memory.hpp>
37 #include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
38 #include <boost/interprocess/sync/interprocess_condition.hpp>
40 #include <SimoxUtility/algorithm/string/string_tools.h>
41 #include <boost/algorithm/string/regex.hpp>
42 #include <boost/regex.hpp>
43 #include <boost/interprocess/sync/file_lock.hpp>
44 #include <boost/interprocess/sync/scoped_lock.hpp>
45 #include <boost/interprocess/sync/sharable_lock.hpp>
46 #include <boost/thread/thread_time.hpp>
55 #define SCRIPT_PATH "ArmarXCore/core/system/cmake/FindPackageX.cmake"
56 #define CACHE_PATH "/ArmarXCMakeCache_" + (getenv("USER")?getenv("USER"):"DUMMY_USER")
65 char* homePathC = getenv(
"HOME");
74 std::shared_ptr<boost::interprocess::file_lock>
getFileLock(std::string lockName,
bool verbose =
false)
79 std::cout <<
"getFileLock( path = " << path <<
")" << std::endl;
81 if (!std::filesystem::exists(path))
85 std::cout <<
"path does not exist" << std::endl;
87 if (!std::filesystem::create_directories(path))
91 std::cout <<
"failed to create directories" << std::endl;
93 return std::shared_ptr<boost::interprocess::file_lock>();
96 path +=
"/" + lockName;
99 std::cout <<
"lock file = " << path << std::endl;
101 if (!std::filesystem::exists(path))
105 std::cout <<
"touch " << path << std::endl;
108 std::ofstream file(path);
113 std::cout <<
"build lock with " << path << std::endl;
115 return std::shared_ptr<boost::interprocess::file_lock>(
new boost::interprocess::file_lock(path.c_str()));
121 std::shared_ptr<boost::interprocess::file_lock> lock(
getFileLock(name,
false));
149 static std::mutex mx;
153 using ScopedFileLockPtr = std::shared_ptr<boost::interprocess::scoped_lock<boost::interprocess::file_lock>>;
160 boost::get_system_time() + boost::posix_time::milliseconds(50)));
161 while (!lockPtr->owns())
163 lockPtr->timed_lock(boost::get_system_time() + boost::posix_time::milliseconds(50));
170 auto start = IceUtil::Time::now();
171 std::string path = std::filesystem::temp_directory_path().string() +
CACHE_PATH;
172 path +=
"/" + packageName;
173 if (!std::filesystem::exists(path))
180 const auto writeTime = std::filesystem::last_write_time(path);
181 const auto now = decltype(writeTime)::clock::now();
182 long age = std::chrono::duration_cast<std::chrono::seconds>(now - writeTime).count();
184 boost::interprocess::sharable_lock<boost::interprocess::file_lock> e_lock(*
CacheFileLock());
186 auto dura = (IceUtil::Time::now() - start).toMilliSecondsDouble();
189 ARMARX_INFO_S << packageName <<
" from cache locked for " << dura;
204 auto start = IceUtil::Time::now();
205 std::string path = std::filesystem::temp_directory_path().string() +
CACHE_PATH;
206 if (!std::filesystem::exists(path))
208 if (!std::filesystem::create_directories(path))
213 path = path +
"/" + packageName;
214 boost::interprocess::scoped_lock<boost::interprocess::file_lock> e_lock(*
CacheFileLock());
218 std::ofstream file(path);
219 file << packageContent;
222 auto dura = (IceUtil::Time::now() - start).toMilliSecondsDouble();
225 ARMARX_INFO_S << packageName <<
" update cache locked for " << dura;
230 boost::interprocess::interprocess_upgradable_mutex*
memoryMutex =
nullptr;
238 packageName(
simox::alg::trim_copy(packageName))
240 if (this->packageName.empty())
242 ARMARX_WARNING <<
"CMakePackageFinder: Package name must not be empty";
244 static std::string scriptPath;
249 if (scriptPath.empty())
253 auto start = IceUtil::Time::now();
255 auto dura = (IceUtil::Time::now() - start);
257 if (dura.toMilliSeconds() > 10000)
259 ARMARX_INFO_S <<
"Cmakefinder for initial core search took long - Duration: " << dura.toMilliSeconds();
264 ARMARX_WARNING_S <<
"Finding FindPackageX.cmake failed - trying again with different path";
276 auto start = IceUtil::Time::now();
277 std::string resultStr;
281 if (!packagePath.empty())
283 resultStr =
ExecCommand(
"cd " + tmpDir +
"; cmake -DPACKAGE=" + this->packageName +
" -DPACKAGEBUILDPATH" + (usePackagePathOnlyAsHint ?
"Hint" :
"") +
"=" + packagePath.string() +
" -P " + scriptPath, result, suppressStdErr);
287 resultStr =
ExecCommand(
"cd " + tmpDir +
"; cmake -DPACKAGE=" + this->packageName +
" -P " + scriptPath, result, suppressStdErr);
299 auto dura = (IceUtil::Time::now() - start);
301 if (dura.toMilliSeconds() > 10000)
303 ARMARX_INFO_S <<
"Cmakefinder took long for package " << packagePath <<
" - Duration: " << dura.toMilliSeconds();
306 std::vector<std::string> resultList;
317 std::vector<std::string> result;
318 boost::split_regex(result,
323 for (
size_t i = 0; i < result.size(); i++)
325 simox::alg::trim(result[i]);
327 if (result[i].
empty())
329 result.erase(result.begin() + i);
341 auto start = IceUtil::Time::now();
345 std::stringstream
str;
346 str <<
"cmake --find-package -DNAME=" <<
packageName <<
" -DLANGUAGE=CXX -DCOMPILER_ID=GNU -DMODE=LINK";
356 auto dura = (IceUtil::Time::now() - start).toMilliSecondsDouble();
374 auto start = IceUtil::Time::now();
380 start = IceUtil::Time::now();
384 std::stringstream
str;
385 str <<
"cd " + tmpDir +
";cmake --find-package -DNAME=" <<
packageName <<
" -DLANGUAGE=CXX -DCOMPILER_ID=GNU -DMODE=COMPILE";
396 auto dura = (IceUtil::Time::now() - start).toMilliSecondsDouble();
414 auto start = IceUtil::Time::now();
417 command +=
" 2>/dev/null";
420 FILE* fp = popen(command.c_str(),
"r");
424 while (fgets(line,
sizeof line, fp))
429 result = pclose(fp) / 256;
430 auto dura = (IceUtil::Time::now() - start).toMilliSecondsDouble();
433 ARMARX_INFO_S <<
"ExecCommand took " << dura <<
" \n command: " << command;
440 std::vector<std::string> result;
441 using namespace std::filesystem;
447 for (; *env; ++env) {
448 const std::string envVar(*env);
449 ARMARX_DEBUG <<
"Retrieved environment variable " << envVar;
452 if(not (elements.size() == 2))
457 const std::string& envVarName = elements.front();
458 const std::string& envVarValue = elements.back();
462 const std::string
packageName = simox::alg::remove_suffix(envVarName,
"_DIR");
469 if (pckFinder.packageFound() && !pckFinder.getBuildDir().empty())
497 std::map<std::string, std::string>::const_iterator it =
vars.find(varName);
499 if (it !=
vars.end())
509 auto depListString =
getVar(
"DEPENDENCIES");
510 std::vector<std::string> resultList =
armarx::Split(depListString,
";",
true,
true);
518 auto depListString =
getVar(
"PACKAGE_DEPENDENCY_PATHS");
520 std::map<std::string, std::string> resultMap;
522 for (
auto& depPairString : resultList)
526 if (depPair.size() < 2)
531 resultMap[depPair.at(0)] = depPair.at(1);
540 const boost::regex e(
"\\-\\- ([a-zA-Z0-9_]+):(.+)");
541 boost::match_results<std::string::const_iterator> what;
543 bool found = boost::regex_search(
input, what, e);
545 for (
size_t i = 1; i < what.size(); i++)
560 simox::alg::trim(varName);
561 simox::alg::trim(content);
576 for (
size_t i = 0; i < resultList.size(); i++)
578 simox::alg::trim(resultList[i]);
580 if (resultList[i].
empty())
582 resultList.erase(resultList.begin() + i);
611 const std::string tmpDir =
"/tmp";
612 std::string result = tmpDir;
613 char* username = getenv(
"USER");
616 std::string usernameString = std::string(username);
617 simox::alg::trim(usernameString);
618 result +=
"/armarxcmake-" + usernameString;
619 if (!std::filesystem::exists(result))
621 if (!std::filesystem::create_directories(result))
632 const boost::regex e(
"\\$C\\{([a-zA-Z0-9_\\-]+):([a-zA-Z0-9_\\-]+)\\}");
633 boost::match_results<std::string::const_iterator> what;
634 bool found = boost::regex_search(
string, what, e);
635 std::map<std::string, CMakePackageFinder> finders;
638 for (
size_t i = 1; i < what.size(); i += 3)
640 std::string
package = what[i];
641 auto it = finders.find(package);
642 if (it == finders.end())
648 std::string var = what[i + 1];
651 auto envVar = it->second.getVar(var);
652 string = boost::regex_replace(
string, e, std::string(envVar));
653 ARMARX_DEBUG <<
"Replacing '" << var <<
"' with '" << std::string(envVar) <<
"'";
663 return getVar(
"EXECUTABLE");
668 namespace fs = std::filesystem;
670 const fs::path componentReportFilename =
671 fs::path(
getBuildDir()) /
"component_executables_report.txt";
672 if (fs::exists(componentReportFilename))
674 std::ifstream componentReportFile(componentReportFilename);
675 if (componentReportFile.bad())
677 ARMARX_WARNING <<
"Could not load file: " << componentReportFilename;
681 const std::string content(std::istreambuf_iterator<char>{componentReportFile}, {});
686 if (
vars.count(
"EXECUTABLE") > 0)
691 ARMARX_WARNING <<
"No component executables available. Check if `" <<
packageName <<
"/build/component_executables_report.txt` is generated properly and EXECUTABLE variable (legacy).";