add target_information()

Print from: pvxinfo -D
and new iocsh iocsh pvxs_target_info()
This commit is contained in:
Michael Davidsaver
2020-12-13 12:07:37 -08:00
parent 4145e482b9
commit 47882d759d
8 changed files with 182 additions and 6 deletions
+2
View File
@@ -136,3 +136,5 @@ Misc. utility code. ::
.. doxygenfunction:: pvxs::cleanup_for_valgrind
.. doxygenclass:: pvxs::SigInt
.. doxygenfunction:: pvxs::target_information
+16 -4
View File
@@ -72,6 +72,17 @@ void pvxsr(int detail)
}
}
void pvxs_target_info()
{
try {
std::ostringstream capture;
target_information(capture);
printf("%s", capture.str().c_str());
} catch(std::exception& e) {
fprintf(stderr, "Error in %s : %s\n", __func__, e.what());
}
}
// index_sequence from:
//http://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
@@ -127,11 +138,11 @@ struct ToStr { typedef const char* type; };
template<typename ...Args>
struct Reg {
const char* const name;
const char* const argnames[sizeof...(Args)];
const char* const argnames[1+sizeof...(Args)];
constexpr explicit Reg(const char* name, typename ToStr<Args>::type... descs)
:name(name)
,argnames{descs...}
,argnames{descs..., 0}
{}
template<void (*fn)(Args...), size_t... Idxs>
@@ -144,8 +155,8 @@ struct Reg {
template<void (*fn)(Args...), size_t... Idxs>
void doit(index_sequence<Idxs...>)
{
static const iocshArg argstack[sizeof...(Args)] = {{argnames[Idxs], Arg<Args>::code}...};
static const iocshArg * const args[] = {&argstack[Idxs]...};
static const iocshArg argstack[1+sizeof...(Args)] = {{argnames[Idxs], Arg<Args>::code}...};
static const iocshArg * const args[] = {&argstack[Idxs]..., 0};
static const iocshFuncDef def = {name, sizeof...(Args), args};
iocshRegister(&def, &call<fn, Idxs...>);
@@ -207,6 +218,7 @@ void pvxsRegistrar()
Reg<int>("pvxsl", "detail").ister<&pvxsl>();
Reg<int>("pvxsr", "detail").ister<&pvxsr>();
Reg<>("pvxs_target_info").ister<&pvxs_target_info>();
auto serv = instance.load();
if(!serv) {
+9
View File
@@ -34,9 +34,16 @@ ifeq (,$(PVXS_MAJOR_VERSION))
$(error PVXS_MAJOR_VERSION undefined, problem reading cfg/CONFIG_PVXS_VERSION)
endif
# see below for special case versionNum.h
EXPAND += describe.h
EXPANDVARS += PVXS_MAJOR_VERSION
EXPANDVARS += PVXS_MINOR_VERSION
EXPANDVARS += PVXS_MAINTENANCE_VERSION
EXPANDVARS += EPICS_HOST_ARCH T_A OS_CLASS
ifdef BASE_3_15
EXPANDVARS += CMPLR_CLASS
endif
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
@@ -61,6 +68,7 @@ INC += pvxs/client.h
LIBRARY = pvxs
LIB_SRCS += describe.cpp
LIB_SRCS += log.cpp
LIB_SRCS += unittest.cpp
LIB_SRCS += util.cpp
@@ -118,6 +126,7 @@ include $(TOP)/configure/RULES_PVXS_MODULE
$(MKDIR) $(COMMON_DIR)/pvxs
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
describe$(DEP): describe.h
util$(DEP): $(COMMON_DIR)/$(GENVERSION)
ifndef GENVERSIONHEADER
+132
View File
@@ -0,0 +1,132 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#if !defined(_WIN32)
# include <sys/utsname.h>
#endif
#include <osiSock.h>
#include <dbDefs.h>
#include <epicsThread.h>
#include <pvxs/util.h>
#include <pvxs/client.h>
#include <pvxs/server.h>
#include "evhelper.h"
#include "describe.h"
namespace pvxs {
std::ostream& target_information(std::ostream& strm)
{
strm<<indent{}<<"Host: "<<EPICS_HOST_ARCH<<"\n";
strm<<indent{}<<"Target: "<<T_A<<" "<<OS_CLASS;
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
strm<<" "<<CMPLR_CLASS;
#endif
strm<<"\n";
{
strm<<indent{}<<"Toolchain\n";
Indented I(strm);
// standard
strm<<indent{}<<"__cplusplus = "<<__cplusplus<<"\n";
// compiler
#ifdef __clang__
strm<<indent{}<<"clang "<<__clang_version__<<"\n";
#endif
#ifdef __GNUC__
strm<<indent{}<<"GCC "<<__GNUC__<<"."<<__GNUC_MINOR__<<"."<<__GNUC_PATCHLEVEL__<<"\n";
#endif
#ifdef _GLIBCXX_USE_CXX11_ABI
strm<<indent{}<<"_GLIBCXX_USE_CXX11_ABI = "<<_GLIBCXX_USE_CXX11_ABI<<"\n";
#endif
#ifdef _MSC_VER
strm<<indent{}<<"MSVC "<<_MSC_FULL_VER<<"\n";
#endif
// library
#ifdef __GLIBC__
strm<<indent{}<<"GLIBC "<<__GLIBC__<<"."<<__GLIBC_MINOR__<<"\n";
#endif
#ifdef __UCLIBC__
strm<<indent{}<<"GLIBC "<<__UCLIBC_MAJOR__<<"."<<__UCLIBC_MINOR__<<"."<<__UCLIBC_SUBLEVEL__<<"\n";
#endif
#ifdef _CPPLIB_VER
// Dinkumware c++
strm<<indent{}<<"_CPPLIB_VER "<<_CPPLIB_VER<<"\n";
#endif
#ifdef __GLIBCXX__
strm<<indent{}<<"__GLIBCXX__ "<<__GLIBCXX__<<"\n";
#endif
#ifdef _LIBCPP_VERSION
// clang c++
strm<<indent{}<<"_LIBCPP_VERSION "<<_LIBCPP_VERSION<<"\n";
#endif
}
{
strm<<"Versions\n";
Indented I(strm);
strm<<indent{}<<version_str()<<"\n";
strm<<indent{}<<EPICS_VERSION_STRING<<"\n";
strm<<indent{}<<"libevent "<<event_get_version()<<"\n";
}
{
strm<<indent{}<<"Runtime\n";
Indented I(strm);
SockAttach attach;
evsocket dummy(AF_INET, SOCK_DGRAM, 0);
#if !defined(_WIN32)
utsname info;
if(uname(&info)==0) {
strm<<indent{}<<"uname() -> "<<info.sysname<<" "<<info.nodename<<" "<<info.release<<" "<<info.version<<" "<<info.machine<<"\n";
} else {
strm<<indent{}<<"uname() error "<<errno<<"\n";
}
#endif
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,2)
strm<<indent{}<<"epicsThreadGetCPUs() -> "<<epicsThreadGetCPUs()<<"\n";
#endif
auto localaddr(osiLocalAddr(dummy.sock));
strm<<indent{}<<"osiLocalAddr() -> "<<SockAddr(&localaddr.sa, sizeof(localaddr)).tostring()<<"\n";
strm<<indent{}<<"osiSockDiscoverBroadcastAddresses() ->\n";
Indented J(strm);
for(auto& addr : dummy.interfaces()) {
strm<<indent{}<<addr.tostring()<<"\n";
}
}
{
strm<<indent{}<<"Effective Client config from environment\n";
Indented I(strm);
auto conf(client::Config::fromEnv());
conf.expand();
strm<<conf;
}
{
strm<<indent{}<<"Effective Server config from environment\n";
Indented I(strm);
auto conf(server::Config::fromEnv());
conf.expand();
strm<<conf;
}
strm.flush();
return strm;
}
} // namespace pvxs
+4
View File
@@ -0,0 +1,4 @@
#define EPICS_HOST_ARCH "@EPICS_HOST_ARCH@"
#define T_A "@T_A@"
#define OS_CLASS "@OS_CLASS@"
#define CMPLR_CLASS "@CMPLR_CLASS@"
+12
View File
@@ -156,6 +156,18 @@ private:
int lvl;
};
/** Describe build and runtime configuration of current system.
*
* Print information which may be using for when troubleshooting,
* or creating a bug report.
*
* Printed by CLI "pvxinfo -D" and iocsh "pvxs_target_information".
*
* @returns The same ostream passed as argument.
*/
PVXS_API
std::ostream& target_information(std::ostream&);
} // namespace pvxs
#endif // PVXS_UTIL_H
+2 -1
View File
@@ -25,7 +25,7 @@ namespace {
MAIN(testioc)
{
testPlan(4);
testPlan(5);
testSetup();
testdbPrepare();
@@ -37,6 +37,7 @@ MAIN(testioc)
testdbReadDatabase("testioc.dbd", nullptr, nullptr);
testEq(0, testioc_registerRecordDeviceDriver(pdbbase));
testEq(0, iocshCmd("pvxsr()"));
testEq(0, iocshCmd("pvxs_target_info()"));
testTrue(!!ioc::server());
+5 -1
View File
@@ -29,6 +29,7 @@ void usage(const char* argv0)
" -V Print version and exit.\n"
" -v Make more noise.\n"
" -d Shorthand for $PVXS_LOG=\"pvxs.*=DEBUG\". Make a lot of noise.\n"
" -D Print host troubleshooting information.\n"
" -w <sec> Operation timeout in seconds. default 5 sec.\n"
;
}
@@ -44,7 +45,7 @@ int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "hVvdw:")) != -1) {
while ((opt = getopt(argc, argv, "hVvdDw:")) != -1) {
switch(opt) {
case 'h':
usage(argv[0]);
@@ -60,6 +61,9 @@ int main(int argc, char *argv[])
case 'd':
logger_level_set("pvxs.*", Level::Debug);
break;
case 'D':
target_information(std::cout);
return 0;
case 'w':
timeout = parseTo<double>(optarg);
break;