Skip to content

Commit 16f21d2

Browse files
committed
[projmgr] Introduce IPC server mode
1 parent e1c09ef commit 16f21d2

7 files changed

Lines changed: 244 additions & 14 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ apply_patch(${CMAKE_CURRENT_SOURCE_DIR}/external/xerces-c)
158158
apply_patch(${CMAKE_CURRENT_SOURCE_DIR}/external/yaml-cpp)
159159

160160
# Google Test Framework
161-
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
161+
set(INSTALL_GTEST ON CACHE BOOL "" FORCE)
162162
add_subdirectory(external/googletest)
163163

164164
set_property(TARGET gtest PROPERTY

tools/projmgr/CMakeLists.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,34 @@ SET(PROJMGR_SOURCE_FILES ProjMgr.cpp ProjMgrKernel.cpp ProjMgrCallback.cpp
1616
ProjMgrYamlEmitter.cpp ProjMgrUtils.cpp ProjMgrExtGenerator.cpp
1717
ProjMgrCbuildBase.cpp ProjMgrCbuild.cpp ProjMgrCbuildIdx.cpp
1818
ProjMgrCbuildGenIdx.cpp ProjMgrCbuildPack.cpp ProjMgrCbuildSet.cpp
19-
ProjMgrCbuildRun.cpp ProjMgrRunDebug.cpp
19+
ProjMgrCbuildRun.cpp ProjMgrRunDebug.cpp ProjMgrIpcServer.cpp
2020
)
2121
SET(PROJMGR_HEADER_FILES ProjMgr.h ProjMgrKernel.h ProjMgrCallback.h
2222
ProjMgrParser.h ProjMgrWorker.h ProjMgrGenerator.h ProjMgrXmlParser.h
2323
ProjMgrYamlParser.h ProjMgrLogger.h ProjMgrYamlSchemaChecker.h
2424
ProjMgrYamlEmitter.h ProjMgrUtils.h ProjMgrExtGenerator.h
25-
ProjMgrCbuildBase.h ProjMgrRunDebug.h
25+
ProjMgrCbuildBase.h ProjMgrRunDebug.h ProjMgrIpcServer.h
2626
)
2727

2828
list(TRANSFORM PROJMGR_SOURCE_FILES PREPEND src/)
2929
list(TRANSFORM PROJMGR_HEADER_FILES PREPEND include/)
3030

31+
# cproto-lib
32+
include(FetchContent)
33+
FetchContent_Declare(
34+
cproto-lib
35+
GIT_REPOSITORY https://github.com/brondani/cproto.git
36+
GIT_TAG main
37+
EXCLUDE_FROM_ALL
38+
)
39+
FetchContent_MakeAvailable(cproto-lib)
40+
41+
# projmgrlib
3142
add_library(projmgrlib OBJECT ${PROJMGR_SOURCE_FILES} ${PROJMGR_HEADER_FILES})
3243
target_link_libraries(projmgrlib
3344
PUBLIC
3445
CrossPlatform RteFsUtils RteUtils XmlTree XmlTreeSlim XmlReader
35-
RteModel cxxopts yaml-cpp YmlSchemaChecker)
46+
RteModel cxxopts yaml-cpp YmlSchemaChecker cproto-lib)
3647
target_include_directories(projmgrlib PRIVATE include ${PROJECT_BINARY_DIR})
3748

3849
if(SWIG_LIBS)

tools/projmgr/include/ProjMgr.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020-2024 Arm Limited. All rights reserved.
2+
* Copyright (c) 2020-2025 Arm Limited. All rights reserved.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -12,6 +12,7 @@
1212
#include "ProjMgrGenerator.h"
1313
#include "ProjMgrYamlEmitter.h"
1414
#include "ProjMgrRunDebug.h"
15+
#include "ProjMgrIpcServer.h"
1516

1617
#include <cxxopts.hpp>
1718

@@ -50,6 +51,17 @@ class ProjMgr {
5051
*/
5152
static int RunProjMgr(int argc, char **argv, char** envp);
5253

54+
/**
55+
* @brief get worker object
56+
* @return reference to m_worker
57+
*/
58+
ProjMgrWorker& GetWorker() { return m_worker; };
59+
60+
61+
void SetContextSet(bool value) { m_contextSet = value; }
62+
void SetSolutionFile(const std::string& file) { m_csolutionFile = file; }
63+
void SetRootDir(const std::string& dir) { m_rootDir = dir; }
64+
bool RunConvert();
5365

5466
protected:
5567
/**
@@ -88,12 +100,6 @@ class ProjMgr {
88100
*/
89101
ProjMgrParser& GetParser() { return m_parser; };
90102

91-
/**
92-
* @brief get worker object
93-
* @return reference to m_worker
94-
*/
95-
ProjMgrWorker& GetWorker() { return m_worker; };
96-
97103
/**
98104
* @brief get generator object
99105
* @return reference to m_generator
@@ -130,6 +136,7 @@ class ProjMgr {
130136
ProjMgrGenerator m_generator;
131137
ProjMgrYamlEmitter m_emitter;
132138
ProjMgrRunDebug m_runDebug;
139+
ProjMgrIpcServer m_ipcServer;
133140

134141
std::string m_csolutionFile;
135142
std::string m_cdefaultFile;
@@ -163,7 +170,6 @@ class ProjMgr {
163170
std::set<std::string> m_failedContext;
164171

165172
bool RunConfigure();
166-
bool RunConvert();
167173
bool RunCodeGenerator();
168174
bool RunListPacks();
169175
bool RunListBoards();
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2025 Arm Limited. All rights reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef PROJMGRIPCSERVER_H
8+
#define PROJMGRIPCSERVER_H
9+
10+
#include <map>
11+
#include <string>
12+
13+
/**
14+
* Forward declarations
15+
*/
16+
class ProjMgr;
17+
class ResponseEnvelope;
18+
19+
/**
20+
* @brief projmgr ipc server
21+
*/
22+
class ProjMgrIpcServer {
23+
public:
24+
/**
25+
* @brief class constructor
26+
*/
27+
ProjMgrIpcServer(void);
28+
29+
/**
30+
* @brief class destructor
31+
*/
32+
~ProjMgrIpcServer(void);
33+
34+
/**
35+
* @brief run ipc server
36+
* @param project manager instance
37+
* @return true if terminated successfully, otherwise false
38+
*/
39+
bool Run(ProjMgr* manager);
40+
41+
protected:
42+
ProjMgr* m_manager = nullptr;
43+
std::string ProcessRequest(const std::string& requestBytes, bool& shutdown);
44+
ResponseEnvelope GetVersion(const std::string& payload);
45+
ResponseEnvelope Shutdown(const std::string& payload);
46+
ResponseEnvelope LoadPacks(const std::string& payload);
47+
ResponseEnvelope LoadSolution(const std::string& payload);
48+
ResponseEnvelope ListComponents(const std::string& payload);
49+
};
50+
51+
#endif // PROJMGRIPCSERVER_H

tools/projmgr/include/ProjMgrWorker.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,10 @@ class ProjMgrWorker {
794794
*/
795795
bool CheckRteErrors(void);
796796

797+
bool LoadPacks(ContextItem& context);
798+
bool SetTargetAttributes(ContextItem& context, std::map<std::string, std::string>& attributes);
799+
const std::list<RtePackage*>& GetLoadedPacks(void) { return m_loadedPacks; };
800+
797801
protected:
798802
ProjMgrParser* m_parser = nullptr;
799803
ProjMgrKernel* m_kernel = nullptr;
@@ -833,7 +837,6 @@ class ProjMgrWorker {
833837
bool m_undefCompiler = false;
834838
std::map<std::string, FileNode> m_missingFiles;
835839

836-
bool LoadPacks(ContextItem& context);
837840
bool CheckMissingPackRequirements(const std::string& contextName);
838841
void CheckMissingLinkerScript(ContextItem& context);
839842
bool CollectRequiredPdscFiles(ContextItem& context, const std::string& packRoot);
@@ -844,7 +847,6 @@ class ProjMgrWorker {
844847
bool GetTypeContent(ContextItem& context);
845848
bool GetProjectSetup(ContextItem& context);
846849
bool InitializeTarget(ContextItem& context);
847-
bool SetTargetAttributes(ContextItem& context, std::map<std::string, std::string>& attributes);
848850
bool ProcessPrecedences(ContextItem& context, BoardOrDevice process = BoardOrDevice::None, bool rerun = false);
849851
bool ProcessPrecedence(StringCollection& item);
850852
bool ProcessCompilerPrecedence(StringCollection& item, bool acceptRedefinition = false);

tools/projmgr/src/ProjMgr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Usage:\n\
2323
csolution <command> [<name>.csolution.yml] [options]\n\n\
2424
Commands:\n\
2525
convert Convert user input *.yml files to *.cprj files\n\
26+
ipc Run csolution as inter-process server\n\
2627
list boards Print list of available board names\n\
2728
list configs Print list of configuration files\n\
2829
list contexts Print list of contexts in a <name>.csolution.yml\n\
@@ -63,6 +64,7 @@ ProjMgr::ProjMgr() :
6364
m_extGenerator(&m_parser),
6465
m_worker(&m_parser, &m_extGenerator),
6566
m_emitter(&m_parser, &m_worker),
67+
m_ipcServer(),
6668
m_checkSchema(false),
6769
m_missingPacks(false),
6870
m_updateRteFiles(true),
@@ -180,6 +182,7 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
180182
{"list layers", { false, {context, contextSet, debug, load, clayerSearchPath, quiet, schemaCheck, toolchain, verbose, updateIdx}}},
181183
{"list toolchains", { false, {context, contextSet, debug, quiet, toolchain, verbose}}},
182184
{"list environment", { true, {}}},
185+
{"ipc", { true, {}}},
183186
};
184187

185188
try {
@@ -403,6 +406,12 @@ int ProjMgr::ProcessCommands() {
403406
if (!RunCodeGenerator()) {
404407
return ErrorCode::ERROR;
405408
}
409+
} else if (m_command == "ipc") {
410+
// Run 'ipc' server
411+
ProjMgrLogger::m_silent = true;
412+
if (!m_ipcServer.Run(this)) {
413+
return ErrorCode::ERROR;
414+
}
406415
} else {
407416
ProjMgrLogger::Get().Error("<command> was not found");
408417
return ErrorCode::ERROR;
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Copyright (c) 2025 Arm Limited. All rights reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "ProjMgrIpcServer.h"
8+
#include "ProjMgr.h"
9+
#include "ProductInfo.h"
10+
11+
#include "cproto.pb.h"
12+
13+
#include <iostream>
14+
#include <string>
15+
16+
using namespace std;
17+
18+
ContextItem m_globalContext;
19+
20+
ProjMgrIpcServer::ProjMgrIpcServer(void) {
21+
// Reserved
22+
}
23+
24+
ProjMgrIpcServer::~ProjMgrIpcServer(void) {
25+
// Reserved
26+
}
27+
28+
ResponseEnvelope ProjMgrIpcServer::GetVersion(const std::string& payload) {
29+
ResponseEnvelope envelope;
30+
GetVersionResponse response;
31+
response.set_version(VERSION_STRING);
32+
envelope.set_status(true);
33+
envelope.set_payload(response.SerializeAsString());
34+
return envelope;
35+
}
36+
37+
ResponseEnvelope ProjMgrIpcServer::Shutdown(const std::string& payload) {
38+
ResponseEnvelope envelope;
39+
envelope.set_status(true);
40+
return envelope;
41+
}
42+
43+
ResponseEnvelope ProjMgrIpcServer::LoadPacks(const std::string& payload) {
44+
ResponseEnvelope envelope;
45+
m_manager->GetWorker().LoadPacks(m_globalContext);
46+
envelope.set_status(true);
47+
return envelope;
48+
}
49+
50+
ResponseEnvelope ProjMgrIpcServer::LoadSolution(const std::string& payload) {
51+
LoadSolutionRequest request;
52+
request.ParseFromString(payload);
53+
ResponseEnvelope envelope;
54+
envelope.set_status(true);
55+
return envelope;
56+
}
57+
58+
ResponseEnvelope ProjMgrIpcServer::ListComponents(const std::string& payload) {
59+
RteComponentMap installedComponents = m_globalContext.rteActiveTarget->GetFilteredComponents();
60+
ListComponentsResponse response;
61+
for (const auto& component : installedComponents) {
62+
response.add_component(component.first);
63+
}
64+
ResponseEnvelope envelope;
65+
envelope.set_payload(response.SerializeAsString());
66+
envelope.set_status(true);
67+
return envelope;
68+
}
69+
70+
std::string ProjMgrIpcServer::ProcessRequest(const std::string& requestBytes, bool& shutdown) {
71+
// Registry of requests identifiers mapped to handlers
72+
const unordered_map<int, function<ResponseEnvelope(const string&)>> m_requests = {
73+
{ ID::SHUTDOWN , [&](const string& payload) { return Shutdown(payload); } },
74+
{ ID::GET_VERSION , [&](const string& payload) { return GetVersion(payload); } },
75+
{ ID::LOAD_PACKS , [&](const string& payload) { return LoadPacks(payload); } },
76+
{ ID::LOAD_SOLUTION , [&](const string& payload) { return LoadSolution(payload); } },
77+
{ ID::LIST_COMPONENTS , [&](const string& payload) { return ListComponents(payload); } },
78+
};
79+
80+
// Parse request
81+
RequestEnvelope request;
82+
if (!request.ParseFromString(requestBytes)) {
83+
ResponseEnvelope errorResponse;
84+
errorResponse.set_id(ID::NONE);
85+
errorResponse.set_status(false);
86+
errorResponse.set_error("Failed to parse request");
87+
return errorResponse.SerializeAsString();
88+
}
89+
90+
// Find the correct request handler
91+
auto id = m_requests.find(request.id());
92+
if (id == m_requests.end()) {
93+
ResponseEnvelope errorResponse;
94+
errorResponse.set_id(ID::NONE);
95+
errorResponse.set_status(false);
96+
errorResponse.set_error("Unknown id: " + request.id());
97+
return errorResponse.SerializeAsString();
98+
}
99+
100+
// Call the request handler
101+
auto response = id->second(request.payload());
102+
response.set_id(request.id());
103+
104+
// Set shutdown flag
105+
shutdown = (request.id() == ID::SHUTDOWN);
106+
107+
// Serialize response envelope
108+
return response.SerializeAsString();
109+
}
110+
111+
#ifdef _WIN32
112+
#include <fcntl.h>
113+
#include <io.h>
114+
#endif
115+
116+
bool ProjMgrIpcServer::Run(ProjMgr* manager) {
117+
118+
#ifdef _WIN32
119+
// Force binary mode (prevent \n to \r\n conversion)
120+
_setmode(_fileno(stdout), _O_BINARY);
121+
_setmode(_fileno(stdin), _O_BINARY);
122+
#endif
123+
124+
GOOGLE_PROTOBUF_VERIFY_VERSION;
125+
126+
m_manager = manager;
127+
std::string serializedData;
128+
uint32_t size;
129+
bool shutdown = false;
130+
131+
while (!shutdown) {
132+
// Read size (4 bytes)
133+
std::cin.read(reinterpret_cast<char*>(&size), sizeof(size));
134+
135+
// Read protobuf message
136+
serializedData.resize(size);
137+
std::cin.read(&serializedData[0], size);
138+
139+
// Process request and get response
140+
auto responseData = ProcessRequest(serializedData, shutdown);
141+
142+
// Send size
143+
uint32_t responseSize = responseData.size();
144+
std::cout.write(reinterpret_cast<char*>(&responseSize), sizeof(responseSize));
145+
146+
// Send protobuf message
147+
std::cout.write(responseData.data(), responseSize);
148+
std::cout.flush();
149+
}
150+
return true;
151+
}

0 commit comments

Comments
 (0)