Skip to content

Commit b39d746

Browse files
committed
Allow for autogen bypass, partial fix for #264 #252 #207, ref #303
csp_autogen generates C++ struct bindings at build time, which requires a working Python csp import during the C++ build. Allow that step to be bypassed by checking generated sources into the tree: Findcsp_autogen.cmake now prefers in-source csp_autogen/<name>.{h,cpp} when both are present and only falls back to the generate-at-build-time custom command otherwise. Adds the pregenerated sources for csp/engine and the websocket adapter, along with test_pregenerated_types.py to catch them drifting from what the generator would produce. The generator gains --omit_asserts to drop the static offset/alignment/size assertions, which are only valid for the interpreter and platform that generated them and so cannot be baked into checked-in sources. Generated files are stamped with the command that produced them, imports of csp.impl.enum/struct are deferred to call sites so the module can be imported without a built csp, and csp/core/Platform.h is added to the common includes. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com>
1 parent 1b037b2 commit b39d746

8 files changed

Lines changed: 834 additions & 54 deletions

File tree

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ message("\n${Green}CMake Search Path: ${CMAKE_MODULE_PATH}${ColorReset}")
252252
###########
253253
find_package(csp_autogen REQUIRED)
254254

255-
256255
###################################################################################################################################################
257256
# Dependencies #
258257
################

cpp/cmake/modules/Findcsp_autogen.cmake

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ function(csp_autogen MODULE_NAME DEST_FILENAME HEADER_NAME_OUTVAR SOURCE_NAME_OU
1818
cmake_path(SET CSP_AUTOGEN_MODULE_PATH NORMALIZE "${CSP_AUTOGEN}")
1919
cmake_path(SET CSP_AUTOGEN_DESTINATION_FOLDER NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/csp_autogen")
2020
cmake_path(SET CSP_AUTOGEN_CPP_OUT NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/csp_autogen/${DEST_FILENAME}.cpp")
21+
cmake_path(SET CSP_AUTOGEN_CPP_MAYBE_EXISTING NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/csp_autogen/${DEST_FILENAME}.cpp")
2122
cmake_path(SET CSP_AUTOGEN_H_OUT NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/csp_autogen/${DEST_FILENAME}.h")
23+
cmake_path(SET CSP_AUTOGEN_H_MAYBE_EXISTING NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/csp_autogen/${DEST_FILENAME}.h")
2224

2325
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
2426
set(CSP_AUTOGEN_PYTHONPATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE};${CMAKE_SOURCE_DIR};%PYTHONPATH%)
@@ -49,16 +51,22 @@ function(csp_autogen MODULE_NAME DEST_FILENAME HEADER_NAME_OUTVAR SOURCE_NAME_OU
4951
else()
5052
set(ASAN_PRELOAD_CMD "")
5153
endif()
54+
55+
if (EXISTS "${CSP_AUTOGEN_CPP_MAYBE_EXISTING}" AND EXISTS "${CSP_AUTOGEN_H_MAYBE_EXISTING}")
56+
# Files exist in-source
57+
set(${SOURCE_NAME_OUTVAR} "${CSP_AUTOGEN_CPP_MAYBE_EXISTING}" PARENT_SCOPE )
58+
set(${HEADER_NAME_OUTVAR} "${CSP_AUTOGEN_H_MAYBE_EXISTING}" PARENT_SCOPE )
59+
else()
60+
add_custom_command(OUTPUT "${CSP_AUTOGEN_CPP_OUT}" "${CSP_AUTOGEN_H_OUT}"
61+
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CSP_AUTOGEN_PYTHONPATH}" ${ASAN_PRELOAD_CMD} ${Python_EXECUTABLE} ${CSP_AUTOGEN_MODULE_PATH} -m ${MODULE_NAME} -d ${CSP_AUTOGEN_DESTINATION_FOLDER} -o ${DEST_FILENAME} ${CSP_AUTOGEN_EXTRA_ARGS}
62+
COMMENT "generating csp c++ types from module ${MODULE_NAME}"
63+
DEPENDS mkdir_autogen_${MODULE_TARGETNAME}
64+
${CSP_AUTOGEN_MODULE_PATH}
65+
${CMAKE_SOURCE_DIR}/${MODULE_FILENAME}
66+
${CSP_TYPES_LIBRARY_FOR_AUTOGEN}
67+
)
5268

53-
add_custom_command(OUTPUT "${CSP_AUTOGEN_CPP_OUT}" "${CSP_AUTOGEN_H_OUT}"
54-
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CSP_AUTOGEN_PYTHONPATH}" ${ASAN_PRELOAD_CMD} ${Python_EXECUTABLE} ${CSP_AUTOGEN_MODULE_PATH} -m ${MODULE_NAME} -d ${CSP_AUTOGEN_DESTINATION_FOLDER} -o ${DEST_FILENAME} ${CSP_AUTOGEN_EXTRA_ARGS}
55-
COMMENT "generating csp c++ types from module ${MODULE_NAME}"
56-
DEPENDS mkdir_autogen_${MODULE_TARGETNAME}
57-
${CSP_AUTOGEN_MODULE_PATH}
58-
${CMAKE_SOURCE_DIR}/${MODULE_FILENAME}
59-
${CSP_TYPES_LIBRARY_FOR_AUTOGEN}
60-
)
61-
62-
set(${SOURCE_NAME_OUTVAR} "${CSP_AUTOGEN_CPP_OUT}" PARENT_SCOPE)
63-
set(${HEADER_NAME_OUTVAR} "${CSP_AUTOGEN_H_OUT}" PARENT_SCOPE)
69+
set(${SOURCE_NAME_OUTVAR} "${CSP_AUTOGEN_CPP_OUT}" PARENT_SCOPE)
70+
set(${HEADER_NAME_OUTVAR} "${CSP_AUTOGEN_H_OUT}" PARENT_SCOPE)
71+
endif()
6472
endfunction()
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
// AUTOGENERATED BY CSP_AUTOGEN
3+
// DO NOT MODIFY DIRECTLY
4+
// command: python csp/build/csp_autogen.py -m csp.adapters.websocket_types -d cpp/csp/adapters/websocket/csp_autogen/ -o websocket_types --omit_asserts
5+
6+
#include "websocket_types.h"
7+
#include <csp/python/Common.h>
8+
#include <csp/python/PyStruct.h>
9+
#include <csp/python/PyCspEnum.h>
10+
#include <iostream>
11+
#include <stdlib.h>
12+
#include <Python.h>
13+
14+
namespace csp::autogen
15+
{
16+
17+
#define _offsetof( C, M ) ( ( char * ) &( ( C * ) nullptr ) -> M - ( char * ) 0 )
18+
19+
static void assert_or_die( bool assertion, const char * error )
20+
{
21+
if( !assertion )
22+
{
23+
std::cerr << "Fatal error on import of " << __FILE__ << ": " << error << std::endl;
24+
if( PyErr_Occurred() )
25+
PyErr_Print();
26+
abort();
27+
}
28+
}
29+
30+
31+
bool WebsocketStatus::static_init()
32+
{
33+
if( Py_IsInitialized() )
34+
{
35+
csp::python::AcquireGIL gil;
36+
37+
// initialize EnumMeta from python type if we're in python
38+
PyObject * pymodule = PyImport_ImportModule( "csp.adapters.websocket_types" );
39+
assert_or_die( pymodule != nullptr, "failed to import struct module csp.adapters.websocket_types" );
40+
41+
PyObject * enumType = PyObject_GetAttrString(pymodule, "WebsocketStatus" );
42+
assert_or_die( enumType != nullptr, "failed to find num type WebsocketStatus in module csp.adapters.websocket_types" );
43+
44+
// should add some assertion here..
45+
csp::python::PyCspEnumMeta * pymeta = ( csp::python::PyCspEnumMeta * ) enumType;
46+
s_meta = pymeta -> enumMeta;
47+
}
48+
49+
return true;
50+
}
51+
52+
bool static_init_WebsocketStatus = WebsocketStatus::static_init();
53+
std::shared_ptr<csp::CspEnumMeta> WebsocketStatus::s_meta;
54+
WebsocketStatus WebsocketStatus::ACTIVE = WebsocketStatus::create("ACTIVE");
55+
WebsocketStatus WebsocketStatus::GENERIC_ERROR = WebsocketStatus::create("GENERIC_ERROR");
56+
WebsocketStatus WebsocketStatus::CONNECTION_FAILED = WebsocketStatus::create("CONNECTION_FAILED");
57+
WebsocketStatus WebsocketStatus::CLOSED = WebsocketStatus::create("CLOSED");
58+
WebsocketStatus WebsocketStatus::MESSAGE_SEND_FAIL = WebsocketStatus::create("MESSAGE_SEND_FAIL");
59+
60+
61+
bool WebsocketHeaderUpdate::static_init()
62+
{
63+
64+
if( Py_IsInitialized() )
65+
{
66+
//Note that windows requires we grab the GIL since the windows DLL loading code releases GIL
67+
csp::python::AcquireGIL gil;
68+
69+
// initialize StructMeta from python type if we're in python
70+
PyObject * pymodule = PyImport_ImportModule( "csp.adapters.websocket_types" );
71+
assert_or_die( pymodule != nullptr, "failed to import struct module csp.adapters.websocket_types" );
72+
73+
PyObject * structType = PyObject_GetAttrString(pymodule, "WebsocketHeaderUpdate" );
74+
assert_or_die( structType != nullptr, "failed to find struct type WebsocketHeaderUpdate in module csp.adapters.websocket_types" );
75+
76+
// should add some assertion here..
77+
csp::python::PyStructMeta * pymeta = ( csp::python::PyStructMeta * ) structType;
78+
s_meta = pymeta -> structMeta;
79+
}
80+
81+
return true;
82+
}
83+
84+
bool static_init_WebsocketHeaderUpdate = WebsocketHeaderUpdate::static_init();
85+
csp::StructMetaPtr WebsocketHeaderUpdate::s_meta;
86+
87+
}
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
2+
// AUTOGENERATED BY CSP_AUTOGEN
3+
// DO NOT MODIFY DIRECTLY
4+
// command: python csp/build/csp_autogen.py -m csp.adapters.websocket_types -d cpp/csp/adapters/websocket/csp_autogen/ -o websocket_types --omit_asserts
5+
6+
#ifndef _IN_CSP_AUTOGEN_CSP_ADAPTERS_WEBSOCKET_TYPES
7+
#define _IN_CSP_AUTOGEN_CSP_ADAPTERS_WEBSOCKET_TYPES
8+
9+
#include <csp/core/Exception.h>
10+
#include <csp/core/Platform.h>
11+
#include <csp/engine/Struct.h>
12+
#include <cstddef>
13+
14+
namespace csp::autogen
15+
{
16+
17+
class WebsocketStatus : public csp::CspEnum
18+
{
19+
public:
20+
// Raw value quick access
21+
enum class enum_
22+
{
23+
ACTIVE = 0,
24+
GENERIC_ERROR = 1,
25+
CONNECTION_FAILED = 2,
26+
CLOSED = 3,
27+
MESSAGE_SEND_FAIL = 4
28+
};
29+
30+
// CspEnum types
31+
static WebsocketStatus ACTIVE;
32+
static WebsocketStatus GENERIC_ERROR;
33+
static WebsocketStatus CONNECTION_FAILED;
34+
static WebsocketStatus CLOSED;
35+
static WebsocketStatus MESSAGE_SEND_FAIL;
36+
37+
const char * asCString() const { return name().c_str(); }
38+
const std::string & asString() const { return name(); }
39+
40+
static WebsocketStatus create( enum_ v ) { return s_meta -> create( ( int64_t ) v ); }
41+
static WebsocketStatus create( const char * name) { return s_meta -> fromString( name ); }
42+
static WebsocketStatus create( const std::string & s ) { return create( s.c_str() ); }
43+
44+
enum_ enum_value() const { return ( enum_ ) value(); }
45+
46+
static constexpr uint32_t num_types() { return 5; }
47+
48+
static bool static_init();
49+
50+
WebsocketStatus( const csp::CspEnum & v ) : csp::CspEnum( v ) { CSP_TRUE_OR_THROW( v.meta() == s_meta.get(), AssertionError, "Mismatched enum meta" ); }
51+
52+
private:
53+
54+
static std::shared_ptr<csp::CspEnumMeta> s_meta;
55+
};
56+
57+
class WebsocketHeaderUpdate : public csp::Struct
58+
{
59+
public:
60+
61+
using Ptr = csp::TypedStructPtr<WebsocketHeaderUpdate>;
62+
63+
WebsocketHeaderUpdate() = delete;
64+
~WebsocketHeaderUpdate() = delete;
65+
WebsocketHeaderUpdate( const WebsocketHeaderUpdate & ) = delete;
66+
WebsocketHeaderUpdate( WebsocketHeaderUpdate && ) = delete;
67+
68+
Ptr copy() const { return csp::structptr_cast<WebsocketHeaderUpdate>( Struct::copy() ); }
69+
70+
static WebsocketHeaderUpdate::Ptr create()
71+
{
72+
return Ptr( static_cast<WebsocketHeaderUpdate *>( s_meta -> createRaw() ) );
73+
}
74+
75+
static const csp::StructMetaPtr & meta() { return s_meta; }
76+
77+
78+
const std::string & key() const
79+
{
80+
81+
82+
83+
84+
if( !key_isSet() )
85+
CSP_THROW( csp::ValueError, "field key on struct WebsocketHeaderUpdate is not set" );
86+
87+
return m_key;
88+
}
89+
90+
void set_key( const std::string & value )
91+
{
92+
93+
94+
95+
96+
97+
m_WebsocketHeaderUpdate_mask[0] |= 1;
98+
99+
100+
//TODO employ move semantics where it makes sense
101+
m_key = value;
102+
}
103+
104+
105+
void set_key( const char * value )
106+
{
107+
108+
109+
110+
111+
112+
m_WebsocketHeaderUpdate_mask[0] |= 1;
113+
114+
m_key = value;
115+
}
116+
117+
void set_key( std::string_view value )
118+
{
119+
120+
121+
122+
123+
124+
m_WebsocketHeaderUpdate_mask[0] |= 1;
125+
126+
m_key = value;
127+
}
128+
129+
130+
bool key_isSet() const
131+
{
132+
133+
return m_WebsocketHeaderUpdate_mask[0] & 1;
134+
}
135+
136+
void clear_key()
137+
{
138+
139+
m_WebsocketHeaderUpdate_mask[0] &= ~1;
140+
}
141+
142+
const std::string & value() const
143+
{
144+
145+
146+
147+
148+
if( !value_isSet() )
149+
CSP_THROW( csp::ValueError, "field value on struct WebsocketHeaderUpdate is not set" );
150+
151+
return m_value;
152+
}
153+
154+
void set_value( const std::string & value )
155+
{
156+
157+
158+
159+
160+
161+
m_WebsocketHeaderUpdate_mask[0] |= 2;
162+
163+
164+
//TODO employ move semantics where it makes sense
165+
m_value = value;
166+
}
167+
168+
169+
void set_value( const char * value )
170+
{
171+
172+
173+
174+
175+
176+
m_WebsocketHeaderUpdate_mask[0] |= 2;
177+
178+
m_value = value;
179+
}
180+
181+
void set_value( std::string_view value )
182+
{
183+
184+
185+
186+
187+
188+
m_WebsocketHeaderUpdate_mask[0] |= 2;
189+
190+
m_value = value;
191+
}
192+
193+
194+
bool value_isSet() const
195+
{
196+
197+
return m_WebsocketHeaderUpdate_mask[0] & 2;
198+
}
199+
200+
void clear_value()
201+
{
202+
203+
m_WebsocketHeaderUpdate_mask[0] &= ~2;
204+
}
205+
206+
207+
static bool static_init();
208+
209+
private:
210+
211+
std::string m_key;
212+
std::string m_value;
213+
char m_WebsocketHeaderUpdate_mask[1];
214+
215+
216+
static csp::StructMetaPtr s_meta;
217+
218+
static void assert_mask()
219+
{
220+
221+
}
222+
};
223+
224+
}
225+
#endif

0 commit comments

Comments
 (0)