继续把 interp_execute.cc、interp_queue.cc、interp_find.cc 等 LinuxCNC 源文件纳入直接编译/链接路径,逐步删除临时 convert_g() wrapper 行为

结论:已将核心 LinuxCNC interpreter 源接入 standalone native 编译链接路径,移除 minimal runtime 中的手写 convert_g 行为,并通过 native probe 验证。
This commit is contained in:
2026-06-06 23:49:01 +08:00
commit 5025b0c1a1
95 changed files with 35453 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
//
// IniFile - Ini-file reader and query class
// Copyright (C) 2026 B.Stultiens
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef __LINUXCNC_INI_INIFILE_H
#define __LINUXCNC_INI_INIFILE_H
#ifdef __cplusplus
#warning "Including inifile.h in C++ code is inefficient. You should use the C++ API in inifile.hh instead."
#endif
#include <limits.h>
#include <stddef.h>
#include <stdbool.h>
#include <rtapi_stdint.h>
//
// C-API interface functions
//
#ifdef __cplusplus
extern "C" {
#endif
// There is no real limit in the C++ version. This value is for compatibility.
// It has been increased from the original 256 to PATH_MAX to allow for full
// paths to be properly encapsulated.
#define INI_MAX_LINELEN PATH_MAX
int TildeExpansion(const char *file, char *path, size_t size);
int iniFindString(const char *inipath, const char *tag, const char *section, char *buf, size_t bufsize);
int iniFindBool(const char *inipath, const char *tag, const char *section, bool *result);
int iniFindSInt(const char *inipath, const char *tag, const char *section, rtapi_s64 *result);
int iniFindUInt(const char *inipath, const char *tag, const char *section, rtapi_u64 *result);
int iniFindDouble(const char *inipath, const char *tag, const char *section, double *result);
// Compatibility with existing code
// Maps to iniFindSInt() and truncates the result
int iniFindInt(const char *inipath, const char *tag, const char *section, int *result);
#ifdef __cplusplus
}
#endif
#endif
// vim: ts=4 sw=4

View File

@@ -0,0 +1,504 @@
//
// IniFile - Ini-file reader and query class
// Copyright (C) 2026 B.Stultiens
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef __LINUXCNC_INI_INIFILE_HH
#define __LINUXCNC_INI_INIFILE_HH
#ifndef __cplusplus
#error "inifile.hh cannot be used in C. Please use the C-API in inifile.h"
#endif
#include <string>
#include <optional>
#include <vector>
#include <map>
#include <utility>
#include <algorithm>
#include <climits>
#include <float.h>
#include <rtapi_stdint.h>
//
// IniFile public methods for extraction of values from the ini-file:
//
// Note that selecting the num'th value is the first argument to prevent
// accidents using wrong arguments for the bool/integer/real versions. This way
// you have to select the num'th as the first argument if you really mean to
// use it and cannot be mistaken as the default or min/max values. You can
// just omit the num if you just want the first value as a convenience method.
//
// All find_X_All() methods, except findStringAll(), will perform conversion to
// the requested type. That also means that mixed value content may result in
// errors and dropped results. Use the find_X_All() methods only when you know
// that the values are all supposed to be of the same type.
//
// Helper methods can be used to query the ini-file to get information about
// sections, variables, paths and line numbers:
// bool hasSection(section)
// bool hasVariable(variable, section)
// bool hasVariable(num, variable, section)
// which all map to:
// bool isSet(variable, section)
// bool isSet(num, variable, section)
//
// Ini-file structural content methods:
// std::vector<std::string> findSections()
// std::vector<std::pair<std::string,std::string>> findVariables(section);
// std::pair<std::string, int> lineOf(variable, section)
// std::pair<std::string, int> lineOf(num, variable, section)
//
// General value extraction methods:
// std::vector<std::string> findStringAll(tag, section)
// std::optional<std::string> findString(tag, section)
// std::optional<std::string> findString(num, tag, section)
// std::string findStringV(tag, section, def)
// std::string findStringV(num, tag, section, def)
//
// std::vector<bool> findBoolAll(tag, section)
// std::optional<bool> findBool(tag, section)
// std::optional<bool> findBool(num, tag, section)
// bool findBoolV(tag, section, def)
// bool findBoolV(num, tag, section, def)
//
// std::vector<rtapi_s64> findSIntAll(tag, section)
// std::optional<rtapi_s64> findSInt(tag, section, mini = INT64_MIN, maxi = INT64_MAX)
// std::optional<rtapi_s64> findSInt(num, tag, section, mini = INT64_MIN, maxi = INT64_MAX)
// rtapi_s64 findSIntV(tag, section, def, mini = INT64_MIN, maxi = INT64_MAX)
// rtapi_s64 findSIntV(num, tag, section, def, mini = INT64_MIN, maxi = INT64_MAX)
//
// std::vector<rtapi_u64> findUIntAll(tag, section)
// std::optional<rtapi_u64> findUInt(tag, section, mini = 0, maxi = UINT64_MAX)
// std::optional<rtapi_u64> findUInt(num, tag, section, mini = 0, maxi = UINT64_MAX)
// rtapi_u64 findUIntV(tag, section, def, mini = 0, maxi = UINT64_MAX)
// rtapi_u64 findUIntV(num, tag, section, def, mini = 0, maxi = UINT64_MAX)
//
// std::vector<double> findRealAll(tag, section)
// std::optional<double> findReal(tag, section, mini = -DBL_MAX, maxi = +DBL_MAX)
// std::optional<double> findReal(num, tag, section, mini = -DBL_MAX, maxi = +DBL_MAX)
// double findRealV(tag, section, def, mini = -DBL_MAX, maxi = +DBL_MAX)
// double findRealV(num, tag, section, def, mini = -DBL_MAX, maxi = +DBL_MAX)
//
// Convenience methods using the (usually 32-bit) integer type are provided and
// map to findSInt:
// std::optional<int> findInt(tag, section, mini = INT_MIN, maxi = INT_MAX)
// std::optional<int> findInt(num, tag, section, mini = INT_MIN, maxi = INT_MAX)
// int findIntV(tag, section, def, mini = INT_MIN, maxi = INT_MAX)
// int findIntV(num, tag, section, def, mini = INT_MIN, maxi = INT_MAX)
//
// Implementing (case [in]sensitive) list type values can be done using the
// IniFile::findMap() template function for case sensitive and case insensitive
// compares. The map defined for type T mapping:
// const std::map<const std::string, const T> = {...}
// const std::map<const std::string, const T, IniFile::caseless> = {...}
// for function:
// T findCustom(const IniFile &ini, const std::string &tag, const std::string &section, T def)
//
// Example:
// double findUnits(const IniFile &ini, const std::string &tag, const std::string &section, double def)
// {
// static const std::map<const std::string, const double> unitsMap = {
// { "mm", 1.0 },
// { "metric", 1.0 },
// { "in", 1/25.4 },
// { "inch", 1/25.4 },
// { "imperial", 1/25.4 },
// };
//
// if(auto c = ini.findMap(unitsMap, tag, section))
// return *c;
// return def;
// }
//
// Forward declaration (must be outside namespace)
// This is found in emc/nml_intf/emc.hh
enum EmcJointType : int;
namespace linuxcnc {
// Forward declaration of internal classes
class IniFileContent;
class IniFileTag;
class IniFileSection;
//
// Public facing IniFile operations
//
class IniFile
{
public:
IniFile(const std::string &filePath);
operator bool() const { return isOpen(); }
bool isOpen() const { return _inifilecontent != nullptr; }
bool hasSection(const std::string &section) const {
return isSet(1, "", section);
}
bool hasVariable(int num, const std::string &tag, const std::string &section) const {
return isSet(num, tag, section);
}
bool hasVariable(const std::string &tag, const std::string &section) const {
return hasVariable(1, tag, section);
}
// Returns true if the specified [section]tag is present
bool isSet(int num, const std::string &tag, const std::string &section) const {
if(tag.empty() && section.empty()) {
// No, we don't have nothing
return false;
}
if(tag.empty()) {
// We can have a section that has no variables in it
return (bool)findSection(section);
}
return (bool)findTag(tag, section, num);
}
bool isSet(const std::string &tag, const std::string &section) const {
return isSet(1, tag, section);
}
// Returns the ini-file path and line number of the specified variable
std::pair<std::string,int> lineOf(int num, const std::string &tag, const std::string &section) const;
std::pair<std::string,int> lineOf(const std::string &tag, const std::string &section) const {
return lineOf(1, tag, section);
}
// Get all variables named 'tag' from (optional) section in a vector.
// Returns an empty vector if none found.
std::vector<std::string> findStringAll(const std::string &tag, const std::string &section) const;
std::vector<bool> findBoolAll(const std::string &tag, const std::string &section) const;
std::vector<rtapi_s64> findSIntAll(const std::string &tag, const std::string &section) const;
std::vector<rtapi_u64> findUIntAll(const std::string &tag, const std::string &section) const;
std::vector<double> findRealAll(const std::string &tag, const std::string &section) const;
// Get the num'th variable named 'tag' from (optional) section.
// Returns std::nullopt if not found
std::optional<std::string> findString(int num, const std::string &tag, const std::string &section) const;
std::optional<bool> findBool(int num, const std::string &tag, const std::string &section) const;
std::optional<std::string> findString(const std::string &tag, const std::string &section) const {
return findString(1, tag, section);
}
std::optional<bool> findBool(const std::string &tag, const std::string &section) const {
return findBool(1, tag, section);
}
// Get numerical values with options bounded ranges.
// Returns std::nullopt if not found or out-of-range.
std::optional<rtapi_s64> findSInt(int num, const std::string &tag, const std::string &section,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const;
std::optional<rtapi_u64> findUInt(int num, const std::string &tag, const std::string &section,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const;
std::optional<double> findReal(int num, const std::string &tag, const std::string &section,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const;
std::optional<rtapi_s64> findSInt(const std::string &tag, const std::string &section,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
return findSInt(1, tag, section, mini, maxi);
}
std::optional<rtapi_u64> findUInt(const std::string &tag, const std::string &section,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
return findUInt(1, tag, section, mini, maxi);
}
std::optional<double> findReal(const std::string &tag, const std::string &section,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
return findReal(1, tag, section, mini, maxi);
}
// Get the num'th value with defaults if not found.
std::string findStringV(int num, const std::string &tag, const std::string &section, const std::string &def) const {
if(auto v = findString(num, tag, section))
return *v;
return def;
}
bool findBoolV(int num, const std::string &tag, const std::string &section, bool def) const {
if(auto v = findBool(num, tag, section))
return *v;
return def;
}
std::string findStringV(const std::string &tag, const std::string &section, const std::string &def) const {
return findStringV(1, tag, section, def);
}
bool findBoolV(const std::string &tag, const std::string &section, bool def) const {
return findBoolV(1, tag, section, def);
}
// Find the num'th value within min/max range.
// Returns default value if not found or out-of-range.
// These have a suffix 'V' to counter the overloading ambiguity.
rtapi_s64 findSIntV(int num, const std::string &tag, const std::string &section, rtapi_s64 def,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
if(auto v = findSInt(num, tag, section, mini, maxi))
return *v;
return def;
}
rtapi_u64 findUIntV(int num, const std::string &tag, const std::string &section, rtapi_u64 def,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
if(auto v = findUInt(num, tag, section, mini, maxi))
return *v;
return def;
}
double findRealV(int num, const std::string &tag, const std::string &section, double def,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
if(auto v = findReal(num, tag, section, mini, maxi))
return *v;
return def;
}
rtapi_s64 findSIntV(const std::string &tag, const std::string &section, rtapi_s64 def,
rtapi_s64 mini = INT64_MIN, rtapi_s64 maxi = INT64_MAX) const {
return findSIntV(1, tag, section, def, mini, maxi);
}
rtapi_u64 findUIntV(const std::string &tag, const std::string &section, rtapi_u64 def,
rtapi_u64 mini = 0, rtapi_u64 maxi = UINT64_MAX) const {
return findUIntV(1, tag, section, def, mini, maxi);
}
double findRealV(const std::string &tag, const std::string &section, double def,
double mini = -DBL_MAX, double maxi = +DBL_MAX) const {
return findRealV(1, tag, section, def, mini, maxi);
}
// Convenience methods
std::optional<int> findInt(int num, const std::string &tag, const std::string &section,
int mini = INT_MIN, int maxi = INT_MAX) const {
if(auto v = findSInt(num, tag, section, mini, maxi))
return (int)*v;
return std::nullopt;
}
std::optional<int> findInt(const std::string &tag, const std::string &section,
int mini = INT_MIN, int maxi = INT_MAX) const {
return findInt(1, tag, section, mini, maxi);
}
int findIntV(int num, const std::string &tag, const std::string &section, int def,
int mini = INT_MIN, int maxi = INT_MAX) const {
return (int)findSIntV(num, tag, section, def, mini, maxi);
}
int findIntV(const std::string &tag, const std::string &section, int def,
int mini = INT_MIN, int maxi = INT_MAX) const {
return findIntV(1, tag, section, def, mini, maxi);
}
// Map-search matching of values returning the mapped value.
// Search is case-sensitive.
template<typename T>
std::optional<T> findMap(int num, const std::map<const std::string, const T> &map,
const std::string &tag, const std::string &section = "") const {
if(auto s = findString(num, tag, section)) {
auto const m = map.find(*s);
if(m != map.end()) {
return m->second;
}
}
return std::nullopt;
}
template<typename T>
std::optional<T> findMap(const std::map<const std::string, const T> &map,
const std::string &tag, const std::string &section = "") const {
return findMap(1, map, tag, section);
}
// Map compare function without case
struct caseless {
struct caseless_cmp {
bool operator() (const char &a, const char &b) const {
return std::tolower(a & 0xff) < std::tolower(b & 0xff);
}
};
bool operator() (const std::string &a, const std::string &b) const {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), caseless_cmp());
}
};
// Map-search matching of values returning the mapped value.
// Search is case-insensitive.
template<typename T>
std::optional<T> findMap(int num, const std::map<const std::string, const T, caseless> &map,
const std::string &tag, const std::string &section = "") const {
if(auto s = findString(num, tag, section)) {
auto const m = map.find(*s);
if(m != map.end()) {
return m->second;
}
}
return std::nullopt;
}
template<typename T>
std::optional<T> findMap(const std::map<const std::string, const T, caseless> &map,
const std::string &tag, const std::string &section = "") const {
return findMap(1, map, tag, section);
}
template<typename T>
std::optional<T> static mapMap(const std::map<const std::string, const T, caseless> &map,
const std::string &str) {
auto const m = map.find(str);
if(m != map.end()) {
return m->second;
}
return std::nullopt;
}
//
// Mapping functions for enumerated types so they become consistent
// throughout the code base. They take a string argument and match it to
// the mapped values:
// - mapLinearUnits() maps {mm, metric, in, inch, imperial}
// - mapAngularUnits() maps {deg, degree, grad, gon, rad, radian}
// - mapJointType() maps {LINEAR, ANGULAR}
//
static std::optional<double> mapLinearUnits(const std::string &str);
static std::optional<double> mapAngularUnits(const std::string &str);
static std::optional<EmcJointType> mapJointType(const std::string &str);
// The following find*() both lookup the ini variable and attempt to
// convert to the associated numerical value.
std::optional<double> findLinearUnits(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapLinearUnits(*c);
return std::nullopt;
}
std::optional<double> findAngularUnits(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapAngularUnits(*c);
return std::nullopt;
}
std::optional<EmcJointType> findJointType(int num, const std::string &var, const std::string &sec) const {
if(auto c = findString(num, var, sec))
return mapJointType(*c);
return std::nullopt;
}
double findLinearUnits(const std::string &var, const std::string &sec, double def) const {
if(auto m = findLinearUnits(1, var, sec))
return *m;
return def;
}
double findAngularUnits(const std::string &var, const std::string &sec, double def) const {
if(auto m = findAngularUnits(1, var, sec))
return *m;
return def;
}
EmcJointType findJointType(const std::string &var, const std::string &sec, EmcJointType def) const {
if(auto m = findJointType(1, var, sec))
return *m;
return def;
}
// Return a list of section names from the ini-file
std::vector<std::string> findSections() const;
// Return a list of variable name/value pairs from an optional section in the ini-file
std::vector<std::pair<std::string,std::string>> findVariables(const std::string &section) const;
// The fact that this is here is because of compatibility
// Perform tilde expansion using HOME environment variable.
// Returns the filePath "~/path" as "$HOME/path"
// Zero is returned on success or a negative value (-errno) on failure.
static int tildeExpand(const std::string &filePath, std::string &res);
// Compatibility method
static int TildeExpansion(const std::string &filePath, std::string &res) {
return IniFile::tildeExpand(filePath, res);
}
static std::optional<bool> convertBool(const std::string &val);
static std::optional<rtapi_s64> convertSInt(const std::string &val);
static std::optional<rtapi_u64> convertUInt(const std::string &val);
static std::optional<double> convertReal(const std::string &val);
// split() Tokenize 'str' based on 'delim'
static std::vector<std::string> split(const std::string &delim, const std::string &str);
// Trim leading/trailing or both
static void rtrim(std::string &str) {
size_t n = str.find_last_not_of(IniFile::STR_WS);
if(std::string::npos != n)
str.erase(n+1);
}
static void ltrim(std::string &str) {
if(str.empty())
return;
size_t n = str.find_first_not_of(IniFile::STR_WS);
if(std::string::npos == n)
str.clear(); // Only whitespace
else
str.erase(0, n);
}
static void trim(std::string &str) {
rtrim(str);
ltrim(str);
}
// Trim on a copy and return the trimmed copy
static std::string rtrimcpy(const std::string &str) {
std::string cpy = str;
rtrim(cpy);
return cpy;
}
static std::string ltrimcpy(const std::string &str) {
std::string cpy = str;
ltrim(cpy);
return cpy;
}
static std::string trimcpy(const std::string &str) {
std::string cpy = str;
rtrim(cpy);
ltrim(cpy);
return cpy;
}
// White-space characters for argument to find_first_of() and the like.
// Using static constexpr std::string does not seem to work on Debian 11
// with clang-19 and older than that. Gcc on debian 11 and before doesn't
// support enough C++20 to build LinuxCNC at all.
static constexpr char STR_WS[] =" \t\v\f\r\n";
// This isSpace is guaranteed not to depend on locale
static bool isSpace(char c) {
return std::string::npos != (std::string{STR_WS}).find(c);
}
private:
bool Open(const std::string &filePath);
bool Close() { _inifilecontent = nullptr; _filepath.clear(); return true; }
bool hasOpenError(const std::string &tag, const std::string &section) const;
std::string sectionFromTag(const IniFileTag *val) const;
std::optional<const IniFileSection *> findSection(const std::string &section) const;
std::optional<const IniFileTag *> findTag(const std::string &tag, const std::string &section, int num) const;
std::optional<std::vector<const IniFileTag *>> findTags(const std::string &tag, const std::string &section) const;
std::optional<bool> convertBool(const IniFileTag *val) const;
std::optional<rtapi_s64> convertSInt(const IniFileTag *val) const;
std::optional<rtapi_u64> convertUInt(const IniFileTag *val) const;
std::optional<double> convertReal(const IniFileTag *val) const;
const IniFileContent *_inifilecontent;
std::string _filepath;
};
} // namespace linuxcnc
#endif
// vim: ts=4 sw=4